Educational Codeforces Round 184 (Rated for Div. 2)

B

没什么好说的很简单模拟,要考虑全面

非-1的情况是从两边可以往中间走,也就是左边是<或者右边是>, 注意*可以当作是任意两个

C

起初没什么想法了l,r这两个端点复杂度要压倒<O(n^2)还是太迟操作了,然后大概思考了一小时吧,发现一个事情一开始没有考虑到

假设我们在改变区间的数字用1来表示,题目的最终数列一定是这样的

011100,就是一定是分为2,3个部分(10000,011111,0011100,010000)类似于这样

有点像最大字段和,所以思考一下DP做法,然后很困难的想到可以设dp[i]为当前i位为这一堆1的最后一位,意思是这个i位一定是你这一个区域的最后一个

这样可以保证每个dp[i]是一个合法操作,然后这个状态是可以转移过来的,分两个部分

1、跟着前面并入前面i-1,因为dp[i-1]也一定是1,所以你可以选择和前面的连在一起,因为前面dp[i-1]就是最优的情况了,所以你这样加在后面至少可以保证不算太差

2、你也可以抛弃前面的一堆1,自己作为一个开头,计算一下这样的总价值就好

所以我们就存一下当前操作i时的左端点就可以了,而且计算[l,r]区间价值是可以O(1)的,所以做完了

void solve(){
    int n;cin>>n;
    vector<int>sh(n+1,0),pre(n+1,0);
    for(int i=1;i<=n;i++){
        cin>>sh[i];
        pre[i]=pre[i-1]+sh[i];
    }
    auto find=[&](int l,int r){
        int res=(l+r)*(r-l+1);
        res+=pre[l-1]+(pre[n]-pre[r]);
        return res;
    };
    vector<pii>dp(n+1);
    dp[1].first=pre[n]+2-sh[1];dp[1].second=1;
    for(int i=2;i<=n;i++){
        int l=find(dp[i-1].second,i),r=find(i,i);
        if(r>=l){
            dp[i].second=i;
        }else{
            dp[i].second=dp[i-1].second;
        }
        dp[i].first=max(l,r);
    }
    int ans=0;
    for(int i=1;i<=n;i++)ans=max(ans,dp[i].first);
    cout<<ans<<endl;
    return ;
}

D(待补)数学不太好不太会思考咋做,看着difficulty也不算太高,还是太菜了

posted @ 2025-12-03 00:45  zhzhzhao  阅读(2)  评论(0)    收藏  举报