题解:CF2172L Maximum Color Segment
Solution
感觉不是很难,不懂为什么这么少人过。
首先考虑经典差分转化,相邻两项分别异或起来得到新序列。
那么原题中进行长为
容易发现可以每个
那么问题就转变为了可以进行若干次翻转相邻两位的操作,求最多能得到多少个
然后最后考虑把
但现在有个问题就是如果直接做,分组背包时间复杂度是
发现如果
我们贪心的想一下,怎样构造一个
所以我们只需要对于每个序列枚举到
最后还要考虑一个小 corner case,就是原序列开头与结尾的翻转,可以单独一个数翻转,这时候会多出一条转移式,特判一下即可。
Code
#include<bits/stdc++.h>
#define int long long
#define N 3005
using namespace std;
int n,m,k,a[N],dp[3][N],f[N][N],g[N];
int fl,tot,d[N],t,ans;
char ch,lst;
vector<int>vt[N];
signed main(){
ios::sync_with_stdio(false);
cin>>n>>m>>k,fl=n%k,t=min(m,3*(n/k+5));
for(int i=0;i<n;i++){
cin>>ch;
if(!i){lst=ch;continue;}
a[i]=(lst!=ch),ans+=a[i],vt[i%k].push_back(a[i]),lst=ch;
}
for(int id=0;id<k;id++){
tot=0;
for(int i=0;i<vt[id].size();i++){
if(!vt[id][i]) d[++tot]=i+1;
}
for(int i=1;i<=t;i++)
dp[0][i]=dp[1][i]=dp[2][i]=0;
for(int i=1;i<=tot;i++){
for(int j=t;j;j--){
dp[0][j]=0;
if(i>=2&&j>=d[i]-d[i-1])
dp[0][j]=max(dp[0][j],dp[2][j-(d[i]-d[i-1])]+2);
if(!id&&j>=d[i])
dp[0][j]=max(dp[0][j],dp[1][j-d[i]]+1);
if(id==fl&&j>=vt[id].size()-d[i]+1)
dp[0][j]=max(dp[0][j],dp[1][j-(vt[id].size()-d[i]+1)]+1);
}
for(int j=1;j<=t;j++)
dp[2][j]=max(dp[2][j],dp[1][j]),
dp[1][j]=max(dp[1][j],dp[0][j]);
}
for(int i=1;i<=t;i++) f[id][i]=dp[0][i];
}
for(int i=0;i<k;i++){
for(int j=m;j;j--){
for(int l=1;l<=t;l++){
if(j>=l) g[j]=max(g[j],g[j-l]+f[i][l]);
}
}
}
cout<<g[m]+ans+1;
return 0;
}