当前位置: 首页 > news >正文

寒假第三周周报

        这一周做了挺多场天题赛的,写题速度变快了,但是错误也更容易犯了,回顾学习了挺多知识。天体赛的模拟题很多,而且题目意思有时候很抽象,这时候就一定不能急着下笔,有大体思路再做,不然后面改太慢了。牛客训练营也结束了,感觉并不是很理想,在23级的同学中排到靠后了。还是需要再努力一点。下周蓝桥杯训练就要开始,这周我也终于把驾照给拿到手了,寒假还有一段时间才结束,继续加油,不要懈怠下来。

题目:Multi-Subject Competition(贪心、前缀和

Problem - C - Codeforces

这题目意思是有m个项目,n个人有会的项目和技术水平,从m个项目中选取任意个项目,选取的项目要满足条件,选取的项目都是相同的参与人数。求怎么样选取技术水平最大。

解析:

这题目的描述我赛时理解的很差,这其实就是一个变换了一点的前缀和加贪心的问题,赛时脑子糊涂想复杂,其实就先把每个人的项目和他的能力记录下来,在项目中按非递减排序。然后再开一个前缀和数组,求如果选i个人参加该项目选法(如果技术值小于0,在大于等于i个人之后都不选该项目)最后排序求出最大的技术水平。

代码:

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define pii pair<int,int>
#define pdd pair<double,double>
#define ull unsigned long long
#define endl '\n'
const int N=1e5+7;
const int M=2e5+7;
const int mod=1e9+7;
const double pi=3.1415926535;

vector<int> a[N];
int d[N];
void solve() {
    int n,m;
    cin>>n>>m;
    for (int i=0;i<n;i++) {
        int x,y;
        cin>>x>>y;
        a[x].push_back(y);
    }
    for (int i=1;i<=m;i++) {
         if (!a[i].empty()) sort(a[i].begin(),a[i].end(),greater<int>());//每个项目从大的开始选。
    }
    vector<int> v(n+1,0);//选i个人的情况下的最优
    for (int i=1;i<=m;i++) {
        int res=0;
        int len=a[i].size();
        for (int j=0;j<len;j++) {
            res+=a[i][j];
            if (res<0) break;//如果该项目选当前的人数小于0就不需要选该项目了
            v[j+1]+=res;
        }
    }
    sort(v.begin(),v.end(),greater<int>());
    cout<<v[0]<<endl;
}

signed main(){
    ios::sync_with_stdio(false);std::cin.tie(0);cout.tie(0);
    int T=1;
    //cin>>T;
    while(T--){
        solve();
    }

    return 0;
}

题目:D. Maximum Diameter Graph(构造图

Problem - D - Codeforces

解析:

本题可以先将大于等于2的度的点(假设有k个)相连接(尽量连成一条直线)存边,等于1的点只能做最边上的点,然后再处理等于1的点,连接在度数大于0的点上,存边,如果最后将所有点连完那么就可以构成图,图的直径就是k+p-1,p就是看度大于等于2左右是否还能再加度为1的边;

代码:

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define pii pair<int,int>
#define pdd pair<double,double>
#define ull unsigned long long
#define endl '\n'
const int N=1e6+7;
const int M=2e5+7;
const int mod=1e9+7;
const double pi=3.1415926535;

bool cmp(pii x,pii y) {
    return x.first>y.first;
}

void solve() {
    int n;
    cin>>n;
    vector<pii> a;
    for (int i=1;i<=n;i++) {
        int x;
        cin>>x;
        a.push_back({x,i});
    }
    sort(a.begin(),a.end(),cmp);
    vector<pii> v;
    int pr=a[0].second;
    int len=a.size();
    int xb=-1;
    for (int i=1;i<len;i++) {
        int x=a[i].first,y=a[i].second;
        a[i].first--;
        v.push_back({pr,y});
        pr=y;
        a[i-1].first--;
        xb=i+1;
        if (x==1) {
            break;
        }
    }
    if (xb==-1) {
        cout<<"NO"<<endl;
        return;
    }
    int l=xb;
    int lg=0;
    for (int i=0;i<xb;i++) {
        int y=a[i].second;
        while (l<len&&a[i].first>0) {
            lg=1;
            a[i].first--;
            a[l].first--;
            v.push_back({y,a[l].second});
            l++;
        }
    }
    if (l<n) {
        cout<<"NO"<<endl;
    }
    else {
        cout<<"YES"<<" "<<xb+lg-1<<endl;
        cout<<v.size()<<endl;
        for (auto [x,y]: v) {
            cout<<x<<" "<<y<<endl;
        }
    }

}

signed main(){
    ios::sync_with_stdio(false);std::cin.tie(0);cout.tie(0);
    int T=1;
    //cin>>T;
    while(T--){
        solve();
    }

    return 0;
}

题目:铁刀磨成针

J-铁刀磨成针_2025牛客寒假算法基础集训营6

题意是给你一把攻击力为x,n个回合,并且你还有y个磨刀石每次磨刀增加一点体力,每个回合都可以顺序进行磨刀,和攻击(攻击伤害是刀的攻击力),攻击之后会使刀的攻击力-1。求最大造成伤害。

解析:

这道题可以看出,把刀磨好再砍是最优的,问题是什么时候开始砍,这时候看数据T组y<=1e3,这样复杂度是1e7。开始砍了之后还有两种情况,第一种就是还有磨刀石(每回合边磨边砍),第二种是没有磨刀石了,每次砍完攻击力就会减1.(这是造成了多少攻击就是等差数列了),长度是多少呢?要么到攻击力变为1,要么到回合回合结束,这两种情况下取一个最小值。这道题赛时没写出来,是因为我一直在想分类讨论,没想到挨个枚举开始砍,下次要注意给的数据。

代码:

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define pii pair<int,int>
#define pdd pair<double,double>
#define ull unsigned long long
#define endl '\n'
const int N=1e5+7;
const int M=2e5+7;
const int mod=1e9+7;
const double pi=3.1415926535;

int qh(int a1,int an) {
    int sum=0;
    sum=(2*a1-an+1)*an/2;
    return sum;
}

void solve() {
    int n,x,y;
    cin>>n>>x>>y;
    int mi=min(y,n);//最多磨mi刀
    int ans=0;
    for (int i=1;i<=mi;i++) {//第i天开始砍
        int k=x+i;
        int res=0;
        int an=min(k,n-mi+1);
        res+=(mi-i)*k;
        res+=qh(k,an);//没有磨刀石伤害每天减1;
        ans=max(ans,res);
    }
    cout<<ans<<endl;
}

signed main(){
    ios::sync_with_stdio(false);std::cin.tie(0);cout.tie(0);
    int T=1;
    cin>>T;
    while(T--){
        solve();
    }

    return 0;
}

题目:好伙计猜拳(dp)

B-好伙计猜拳_2025牛客寒假算法基础集训营6

解析:

一个合法序列需要满足的要求其实就是 ai≥ai−1,bi≥bi−1,因此这很像最长上升子序列,最长上升子序列的状态定义是 dp[x] 表示以 x 处的数字结尾的最长上升子序列的长度.这里不同的就是有个交换操作。具体见代码。

代码:

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define pii pair<int,int>
#define pdd pair<double,double>
#define ull unsigned long long
#define endl '\n'
const int N=1e3+7;
const int M=2e5+7;
const int mod=1e9+7;
const double pi=3.1415926535;

void solve() {
    int n, c1, c2;
    cin >> n >> c1 >> c2;
    vector<vector<int>> dp(n + 1, vector<int>(2, 1e14));
    dp[0][0] = 0;
    vector<pair<int, int>> a(n + 1);
    for(int i=1;i<=n;i++) cin >> a[i].first >> a[i].second;
    int ans = 1e14;
    for(int i=1;i<=n;i++) {
        for(int j=i-1;j>=0;j--) {
            if(a[i].first >= a[j].first && a[i].second >= a[j].second) {
                dp[i][0] = min(dp[i][0], dp[j][0] +  (i - j - 1) * c1);
            }
            if(a[i].first >= a[j].second && a[i].second >= a[j].first) {
                dp[i][0] = min(dp[i][0], dp[j][1] +(i - j - 1) * c1);
            }
            if(a[i].second >= a[j].first && a[i].first >= a[j].second) {
                dp[i][1] = min(dp[i][1], c2 + dp[j][0] +  (i - j - 1) * c1);
            }
            if(a[i].second >= a[j].second && a[i].first >= a[j].first) {
                dp[i][1] = min(dp[i][1], c2 + dp[j][1] +  (i - j - 1) * c1);
            }
        }
        ans = min(ans, min(dp[i][0], dp[i][1]) +  (n - i) * c1);
    }
    cout << ans << '\n';
}

signed main(){
    ios::sync_with_stdio(false);std::cin.tie(0);cout.tie(0);
    int T=1;
    cin>>T;
    while(T--){
        solve();
    }

    return 0;
}

题目:L2-2 病毒溯源

解析:

Edge[i]中保存第i种病毒可能产生的变异病毒编号,in[i]中保存编号i的入度,入度为零的病毒为源头病毒,pa[i]中保存病毒由哪种病毒变异而来(上级病毒)。为了保证序列最小,在输入Edge[i]后可对其进行一次排序~然后通过BFS找到变异次数,过程中由Long和ans标记最多变异次数量以及对应的病毒编号,最后通过pa找回完整变异链

代码:

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define pii pair<int,int>
#define pdd pair<double,double>
#define ull unsigned long long
#define endl '\n'
const int N=1e4+7;
const int M=1e4+7;
const int mod=1e9+7;
const double pi=3.1415926535;
int n, k, t, S, Long = 0,  ans, in[10005], pa[10005];
vector<int> F, Edge[10005];
queue<pii> Q;
void solve() {
    cin >> n;
    for (int i = 0; i < n; i++) {
        cin >> k;
        for (int j = 0; j < k; j++) {
            cin >> t;
            in[t]++;
            pa[t] = i;
            Edge[i].push_back(t);
        }
        sort(Edge[i].begin(), Edge[i].end());
    }
    for (int i = 0; i < n; i++) if (in[i] == 0) S = i;
    while(!Q.empty()) Q.pop();
    Q.push({S, 1});
    while (!Q.empty()) {
        int now = Q.front().first, D = Q.front().second;
        Q.pop();
        if (D > Long) {
            Long = D;
            ans = now;
        }
        for (auto nex : Edge[now]) Q.push({nex, D + 1});
    }
    cout << Long << '\n';
    while (ans != S) {
        F.push_back(ans);
        ans = pa[ans];
    }
    F.push_back(S);
    for (int i = F.size() - 1; ~i; --i) {
        cout << F[i];
        if (i != 0) cout << ' ';
    }
}

signed main(){
    ios::sync_with_stdio(false);std::cin.tie(0);cout.tie(0);
    int T=1;
    //cin>>T;
    while(T--){
        solve();
    }

    return 0;
}

题目:C. Li Hua and Chess(交互题

Problem - C - Codeforces

解析:

我们发现,每次询问(1,1)一般情况下会得到列坐标或者横坐标为p=d+1,这时就需要判断是列还是横,这时我们再查询(1,p)和(p,1),如果相等就既是列,又是横。如果该点到(1,p)等于d,那么横坐标就是p,纵坐标就为该点到(p,1)的位置。反之一样。注意交互题需要的一些语句,不然会报错。

代码:

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define pii pair<int,int>
#define pdd pair<double,double>
#define ull unsigned long long
#define endl '\n'
const int N=1e6+7;
const int M=2e5+7;
const int mod=1e9+7;
const double pi=3.1415926535;

int ask(int x,int y) {
    cout<<"? "<<x<<" "<<y<<endl;
    cout.flush();
    int d;
    cin>>d;
    return d;
}
void get(int x,int y) {
    cout<<"! "<<x<<" "<<y<<endl;
    cout.flush();
}
void solve() {
    int n,m;
    cin>>n>>m;
    int d=ask(1,1);
    int p=d+1;
    if (d>=n) {
        int x=ask(1,p)+1;
        get(x,p);
    }
    else if (d>=m) {//超过了列,p就是横
        int y=ask(p,1)+1;
        get(p,y);
    }
    else {
        int a,b;
        a=ask(p,1);
        b=ask(1,p);
        if (a==b&&a==d) {
            get(p,p);
        }
        else if (b==d) {
            get(p,a+1);
        }
        else {
            get(b+1,p);
        }
    }

}

signed main(){
    ios::sync_with_stdio(false);std::cin.tie(0);cout.tie(0);
    int T=1;
    cin>>T;
    while(T--){
        solve();
    }

    return 0;
}

相关文章:

  • 基于JAVA的幼儿园管理系统的设计与实现源码(springboot+vue+mysql)
  • [创业之路-307]:如何解读公司的业绩?它与股价变化的关系?
  • c++中std::thread构造函数的注意事项
  • 【Python】Python入门基础——环境搭建
  • 数据库系统原理——第十章数据恢复技术复习题
  • 学习总结三十四
  • Ubuntu20.04部署stable-diffusion-webui环境小记
  • 题海拾贝:英语作文(map)
  • Selenium定位元素的方法及其语法
  • ubuntu20.04连接airpods pro2
  • LeetCode热题100- 缺失的第一个正数【JavaScript讲解】
  • SpringMVC的工作原理
  • 基于Istio Ambient Mesh的无边车架构:实现零侵入式服务网格的云原生革命
  • ElasticSearch映射分词
  • vue3响应式丢失解决办法(三)
  • Leetcode Hot100 第30题 416.分割等和子集
  • CTM工具箱--系统美化工具箱
  • Leetcode100-春招-矩阵题类
  • 图论入门算法:拓扑排序(C++)
  • Copilot:Excel中的Python高级分析来了
  • 下周或迎外贸“抢出口”高峰,跨境电商敏感货物如何便利化“登机”?
  • 侵害孩子者,必严惩不贷!3名性侵害未成年人罪犯今日执行死刑
  • 老字号“逆生长”,上海制造的出海“蜜”钥
  • 阿联酋与美国达成超过2000亿美元协议
  • “免签圈”扩容,旅游平台:今年以来巴西等国入境游订单显著增加
  • 上海锦江乐园摩天轮正在拆除中,预计5月底6月初拆完