Codeforces Round 939

A
按题意模拟

#include <bits/stdc++.h>
#define int long long
#define ull unsigned long long
int use[105];
void paralysis(){
    int k,q;
    std::cin>>k>>q;
    std::vector<int> a(k+1);
    for (int i=1;i<=k;i++){
        std::cin>>a[i];
    }

    while (q--){
        int n;
        std::cin>>n;
        int len=0,flag=1;
        for (int i=1;i<=n;i++){
            use[++len]=i;
        }
        while (flag){
            flag=0;
            for (int i=1;i<=k;i++){
                if (a[i]>len) break;
                use[a[i]]=0;
                flag=1;
            }
            int temp=len;
            len=0;
            for (int i=1;i<=temp;i++){
                if (!use[i]) continue;
                use[++len]=use[i];
                // std::cout<<use[len]<<" ";
            }
        }
        std::cout<<len<<" ";
    }
    std::cout<<"\n";
}
signed main(){
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    std::cout.tie(nullptr);

    int T=1;
    std::cin>>T;
    while (T--){
        paralysis();
    }
    return 0;
}

B
只有自己手牌中出现两次的牌能得分

#include <bits/stdc++.h>
#define int long long
#define ull unsigned long long
void paralysis(){
    int n;
    std::cin>>n;
    int ans=0;
    std::vector<int> cnt(n+1);
    for (int i=1;i<=n;i++){
        int x;
        std::cin>>x;
        cnt[x]++;
        if (cnt[x]==2){
            ans++;
        }
    }
    std::cout<<ans<<"\n";
}
signed main(){
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    std::cout.tie(nullptr);

    int T=1;
    std::cin>>T;
    while (T--){
        paralysis();
    }
    return 0;
}

C
每次操作序列都为12…n,从最后一行开始,行列交替操作

#include <bits/stdc++.h>
#define int long long
#define ull unsigned long long
using namespace std;
void paralysis(){
    int n;
    std::cin>>n;
    std::vector<std::vector<int>> a(n+1,std::vector<int>(n+1));
    int sum=0;
    for (int i=n;i>=1;i--){
        for (int j=1;j<=n;j++){
            sum+=j-a[i][j];
            a[i][j]=j;

            sum+=j-a[j][i];
            a[j][i]=j;
        }
    }

    std::cout<<sum<<" "<<2*n<<"\n";
    for (int i=n;i>=1;i--){
        std::cout<<"1 "<<i<<" ";
        for (int j=1;j<=n;j++){
            std::cout<<j<<" ";
        }
        std::cout<<"\n";

        std::cout<<"2 "<<i<<" ";
        for (int j=1;j<=n;j++){
            std::cout<<j<<" ";
        }
        std::cout<<"\n";
    }
}
signed main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);

    int T=1;
    cin>>T;
    while (T--){
        paralysis();
    }
    return 0;
}

D
长度为 n n n,每个位置的上限是 n n n,然后从小的数据手玩
0->1
00->01->22
000->001->022->020->021->333
发现存在类似递归的方法

那么对于某个区间,要么转换成 n ∗ n n*n nn,要么不变
做区间dp求最大,记录一下需要操作的区间

// LUOGU_RID: 155892430
#include <bits/stdc++.h>
#define int long long
#define ull unsigned long long
using namespace std;
void paralysis(){
    int n;
    cin>>n;
    vector<int> sum(n+1);
    vector<vector<int>> f(n+1,vector<int>(n+1)),pos(n+1,vector<int>(n+1));
    for (int i=1;i<=n;i++){
        cin>>sum[i];
        sum[i]+=sum[i-1];
    }

    for (int len=1;len<=n;len++){
        for (int i=1;i+len-1<=n;i++){
            int j=i+len-1;
            pos[i][j]=-1;
            f[i][j]=sum[j]-sum[i-1];
            if (len*len>f[i][j]){
                pos[i][j]=0;
                f[i][j]=len*len;
            }
            for (int k=i;k<j;k++){
                if (f[i][k]+f[k+1][j]>f[i][j]){
                    pos[i][j]=k;
                    f[i][j]=f[i][k]+f[k+1][j];
                }
            }
        }
    }
    vector<pair<int,int>> ans;
    function<void(int,int,int)> write=[&](int x,int top,int now){
        if (now==1){
            ans.push_back({x,x});
            return;
        }
        for (int i=now-1;i>=1;i--){
            write(x,top,i);
            for (int j=1;j<i;j++){
                ans.push_back({x+j-1,x+j-1});
            }
        }
        ans.push_back({x,x+now-1});
    };

    function<void(int,int)> dfs=[&](int l,int r){
        if (pos[l][r]==-1){
            return;
        }
        if (pos[l][r]==0){
            for (int i=l;i<=r;i++){
                if (sum[i]-sum[i-1]){
                    ans.push_back({i,i});
                }
            }
            write(l,r-l+1,r-l+1);
            return;
        }
        dfs(l,pos[l][r]);
        dfs(pos[l][r]+1,r);
    };

    dfs(1,n);
    cout<<f[1][n]<<" "<<ans.size()<<"\n";
    for (auto [x,y]:ans){
        cout<<x<<" "<<y<<"\n";
    }
}
signed main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);

    int T=1;
    // cin>>T;
    while (T--){
        paralysis();
    }
    return 0;
}

E
简单版本,全局考虑,最后存活的怪物旁边不会有怪物
再往前推,场数少时,最后存活的怪物右边有怪物。
假设某个状态存活的怪物右边的右边有怪物,即 x − > y − > z x->y->z x>y>z(血量)
考虑 z z z 最大血量能撑多久,计算得 ( y − x ) + ( y − 2 ∗ x ) + . . . + ( y % x ) (y-x)+(y-2*x)+...+(y\%x) (yx)+(y2x)+...+(y%x),大致求出是轮数是 y / x y/x y/x级别的,最大就是 y y y级别的。
总结一下就是经过最多 y y y轮,造成 y ∗ y y*y yy级别的伤害,反推得最多经过 z \sqrt z z

所以模拟跑几千轮,最后血量大于0的连通块个数即为答案

困难版同样的分析方法,可得跑 a 1 3 a^{1 \over 3} a31轮后,会出现 x − > y − > z x->y->z x>y>z的连通块,然后分析一下 y y y z z z 谁先死,其它做法和简单版本相同

// LUOGU_RID: 155896350
#include <bits/stdc++.h>
#define ll long long
#define ull unsigned long long
using namespace std;
void paralysis(){
    int n;
    cin>>n;
    vector<int> a(n+1);
    for (int i=1;i<=n;i++){
        cin>>a[i];
    }

    for (int l=0;l<=1500;l++){
        for (int i=1;i<=n;i++){
            a[i]=max(0,a[i]);
            if (a[i]>0){
                a[i%n+1]-=a[i];
            }
        }
    }


    vector<int> ans;
    for (int i=1;i<=n;i++){
        int x=i+1,y=i+2;
        while (x>n) x-=n;
        while (y>n) y-=n;
        if (a[i]>0&&a[x]>0&&a[y]>0){
            ll res=1LL*(a[x]-a[i]+a[x]%a[i])*(1+(a[x]-a[i]-a[x]%a[i])/a[i])/2;
            if (i==n) res+=a[x];
            if (res<a[y]){
            }else{
                a[y]=0;
            }
            a[x]=0;
        }
    }

    for (int i=1;i<=n;i++){
        if (a[i]>0&&a[i%n+1]>0){
            a[i%n+1]=0;
        }
    }


    for (int i=1;i<=n;i++){
        if (a[i]>0){
            ans.emplace_back(i);
        }
    }
    cout<<ans.size()<<"\n";
    for (auto x:ans){
        cout<<x<<" ";
    }
    cout<<"\n";
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);

    int T=1;
    cin>>T;
    while (T--){
        paralysis();
    }
    return 0;
}
  • 26
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Codeforces Round 887是一个程序设计竞赛活动,由Codeforces组织举办。根据引用中的代码,该竞赛的题目要求解决一个序列操作的问题。给定一个长度为n的序列,通过执行一系列操作,使得序列变得非sorted,即非严格递增。具体操作是将序列中[1, i]范围内的数字全部加一,同时将[i+1, n]范围内的数字全部减一。问题要求求解最少需要执行多少次操作才能达到要求。 引用中的代码给出了解决这个问题的实现。代码首先读入序列的长度n和序列a。然后通过判断序列是否已经是非sorted,如果是则直接输出0。接下来,代码遍历序列,求出相邻两个数字的差的最小值。最后,计算出最少需要执行的操作次数,并输出结果。 需要注意的是,引用中的代码只是给出了解决问题的一种实现方式,并不代表Codeforces Round 887的具体题目和解答。要了解该竞赛的具体信息,需要参考Codeforces官方网站或相关资料。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [Codeforces Round 887 (Div. 2)](https://blog.csdn.net/qq_36545889/article/details/131905067)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值