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也不算太高,还是太菜了

浙公网安备 33010602011771号