CF B、C题补题集合

Codeforces Round 959 sponsored by NEAR (Div. 1 + Div. 2)

只有C题的题解哟

C. Hungry Games

思路:求这么多区间数,一般都会考虑动态规划,我们将dp[i]记为左端为i时满足题目要求的区间数,我们考虑这样一个问题:当我们以毒性值为0时去找蘑菇, 很明显当我们找到<=x的最后一个蘑菇时,下一个就要清零,这时候我们就又变成了毒性值为0时去找蘑菇,所以关键就是找到这个节点,让毒性值清0。记这个点为j,那从j+1开始就又变成了相同的问题。

所以状态转移方程为:dp[ i ] = dp[ j] +j -i-1; 如何寻找那个大于x的最小的j呢,我们只需要upper_bound去寻找就好了,

#include <bits/stdc++.h>
using namespace std;
//using ll =  long long;
#define int long long
#define endl '\n'
void fast ()
{ios::sync_with_stdio(0); cin.tie(0);  cout.tie(0);}
const int maxn = 2e5+100;
//#define pii pair<int,int> 

void solve ()
{
    int n,k ;cin >> n >> k;
    vector<int> a(n+1);
    for(int i=1;i<=n;i++){
        cin >> a[i];
    }
    partial_sum(a.begin()+1,a.end(),a.begin()+1); //求前缀和
    vector<int> dp(n+2,0);
    for(int i=n-1;i>=0;i--){ //dp[i]表示i为左端点的区间数
        int j = upper_bound(a.begin(),a.end(),a[i]+k)-a.begin(); 
        dp[i] = dp[j]+j-i-1;
    }
    cout<<accumulate(dp.begin(),dp.end(),0ll)<<endl; //注意这里必须开ll
    
}


signed main ()
{
    fast();
    int t; cin >>t;
    while(t--){
       solve(); 
    }
    return 0;
}

Codeforces Round 960 (Div. 2)

B. Array Craft

思路:将x,y两边设置为以-1为首的正负1交替,x,y内部全为1即可

void solve ()
{
    int n,x,y; cin >>n>>x>>y;
    vector<int>ans(n+1,0);
    for(int i=x+1;i<=n;i++){ //将两边设为正负1交替
        if((x+1)%2 ==1){
            if(i%2==1) ans[i] =-1;
            else ans[i] =1;
        }
        else {
            if(i%2 ==0) ans[i] =-1;
            else ans[i] =1;
        }
    }
    for(int i=y-1;i>=1;i--){ //将两边设为正负1交替
        if((y-1)%2 ==1){
            if(i%2==1) ans[i] =-1;
            else ans[i] =1;
        }
        else {
            if(i%2 ==0) ans[i] =-1;
            else ans[i] =1;
        }
    }
    for(int i=y;i<=x;i++){ //中间设定为1
        ans[i] =1;
    }
    for(int i=1;i<=n;i++){
        cout<<ans[i]<<" ";
    }
    cout<<endl;
}

C. Mad MAD Sum

思路:我们先考虑一组数据:1 1 2 2 3 3我们会发现,通过变换,每次变换之后数组为:

0 1 1 2 2 3 ->0 0 1 1 2 2 ->0 0 0 1 1 2->.......

当数组中有重复出现数字,每次数组都是向右平移,这样的规律让我们计算每次数组的sum时不必要去再遍历数组。

那什么时候我们可以获得这样的所有数字都重复出现的数组呢?

我们会发现只要正常进行两次操作,所有数组都会变成所有数字至少出现两次的情况

AC代码:

#include <bits/stdc++.h>
using namespace std;
//using ll =  long long;
#define int long long
#define endl '\n'
void fast ()
{ios::sync_with_stdio(0); cin.tie(0);  cout.tie(0);}
const int maxn = 2e5+10;
//#define pii pair<int,int> 
int vis[maxn];
void solve ()
{
    int n; cin >>n;
    vector<int> a(n+1,0);
    int sum =0;
    int mad =0; //最大重复出现数
    int ans =0;
    for(int i=1;i<=n;i++){
        cin >> a[i];
        ans+=a[i];
    }
    for(int i=1;i<=n;i++){  //进行第一次变换
        vis[a[i]]++;
        if(vis[a[i]] >1){
            mad = max(mad,a[i]);
        }
        a[i] =mad;
    }
    for(int i=1; i<=n;i++){ //变换一次之后ans
        ans+=a[i];
    }
    memset(vis,0,sizeof(vis));
    mad = 0;
    for(int i=1;i<=n;i++){  //进行第二次变换
        vis[a[i]]++;
        if(vis[a[i]] >1){
            mad = max(mad,a[i]);
        }
        a[i] =mad;
    }
    /*for(int i=1;i<=n;i++){
        cout<<a[i]<<" ";
    }
    cout<<endl;*/
    for(int i=1; i<=n;i++){ //变换二次之后ans
        sum+=a[i];   //sum第二次变换之后的和
    }
    //cout<<sum<<" "<<ans<<endl;
    for(int i=n;sum!=0;i--){
        ans+=sum;
        sum-=a[i];
    }
    cout<<ans<<endl;
    memset(vis,0,sizeof(vis));
}


signed main ()
{
    fast();
    int t; cin >>t;
    while(t--){
       solve(); 
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值