长度为k(k<=20)的01串s[]和t[],不保证二者的01数量相同,
现在有n(n<=1e6)个小精灵,
第i个小精灵可以把s串的第ai和第bi两个位置的值互换,
现在你要选择一个长度至少为m(m<=n)的连续区间,
不妨设为[l,r],则需要依次将(al,bl)...(ar,br)这些位置的值互换,
你需要令操作后的s[],和t[]的相似度最大,相似度定义为对应位置数字相同的个数
输出这个最大相似度,并输出操作的连续区间的左右端点[l,r]
官方题解+boboniu代码
首先,如果固定左端点l,则顺序执行操作至右端点r即可,但l操作转移到l+1时,比较难撤销掉,
所以,可以考虑将t串也进行一次l操作,二者位置同时换,则抵消掉了l的影响
开一个映射,p[]表示当前的数组始终执行换位操作,p[i]表示最初第i位的值现在在pi的位置,
题解1:
官方题解,
记s串中1的数量为o1,t串中1的数量为o2,
二者公共的1的数量为same,二者不相同的位数为x,相似度为y,串长为k
则,o1+o2-2*same=x=y-k,为了最大化y,则最大化same,所以最大相似度和最大公共1是等价的,
dp[0][state]表示s串换成state这个状态最左端的操作下标l,
dp[1][state]表示t串换成state这个状态最右端的操作下标r,
如果r-l>=m,说明[l+1,r]这段操作可行,
但实际二者的state可能并不完全一致,所以sosdp枚举子集,将子集的状态的l和r更新,
倒序枚举子集并下放,找到state相同的满足r-l>=m的状态来更新答案,
其中state中1的个数被认为是最大公共1的个数,统计即可
题解2:
dp两个数组仍与题解1一致,考虑固定一个,用另一个去更新状态
枚举扰动值c,表示当前dp[0][state]中,state最多允许发生c位变化时,最左端的操作下标l
有c位是错乱的情况下,答案为k-c,转移则考虑本轮将dp[0][state]中的一位1发生变化,使其更新相邻状态的l值
#include<bits/stdc++.h>
using namespace std;
const int N=20,M=1<<20,INF=0x3f3f3f3f;
int n,m,k,a,b,x,y,o1,o2;
int ans,pl,pr;
int dp[2][M+5],p[N+5];
char s[N+5],t[N+5];
void g(int &x,int &y){
x=y=0;
for(int j=0;j<k;++j){
if(s[j]=='1')x|=(1<<p[j]);
if(t[j]=='1')y|=(1<<p[j]);
}
}
int main(){
scanf("%d%d%d",&n,&m,&k);
scanf("%s%s",s,t);
for(int i=0;i<k;++i){
p[i]=i;
o1+=(s[i]=='1');
o2+=(t[i]=='1');
}
memset(dp[0],INF,sizeof dp[0]);//min
memset(dp[1],0,sizeof dp[1]);//max
g(x,y);dp[0][x]=0;dp[1][y]=0;
for(int i=1;i<=n;++i){
scanf("%d%d",&a,&b);
a--;b--;swap(p[a],p[b]);
g(x,y);dp[0][x]=min(dp[0][x],i);dp[1][y]=max(dp[1][y],i);
}
for(int i=(1<<k)-1;i>=0;--i){
int tmp=k-(o1+o2-2*__builtin_popcount(i));
if(dp[1][i]-dp[0][i]>=m){
if(ans<tmp){
ans=tmp;
pl=dp[0][i]+1;//dp[0][i]:[1,l-1]
pr=dp[1][i];//dp[1][i]:[1,r]
}
}
for(int j=0;j<k;++j){
if(i>>j&1){
dp[0][i^(1<<j)]=min(dp[0][i^(1<<j)],dp[0][i]);
dp[1][i^(1<<j)]=max(dp[1][i^(1<<j)],dp[1][i]);
}
}
}
printf("%d\n",ans);
printf("%d %d",pl,pr);
return 0;
}
#include<bits/stdc++.h>
using namespace std;
const int N=20,M=1<<20,INF=0x3f3f3f3f;
int n,m,k,a,b,x,y;
int dp[2][M+5],p[N+5],tmp[M+5];
char s[N+5],t[N+5];
void g(int &x,int &y){
x=y=0;
for(int j=0;j<k;++j){
if(s[j]=='1')x|=(1<<p[j]);
if(t[j]=='1')y|=(1<<p[j]);
}
}
int main(){
scanf("%d%d%d",&n,&m,&k);
scanf("%s%s",s,t);
for(int i=0;i<k;++i){
p[i]=i;
}
memset(dp[0],INF,sizeof dp[0]);//min
memset(dp[1],0,sizeof dp[1]);//max
g(x,y);dp[0][x]=0;dp[1][y]=0;
for(int i=1;i<=n;++i){
scanf("%d%d",&a,&b);
a--;b--;swap(p[a],p[b]);
g(x,y);dp[0][x]=min(dp[0][x],i);dp[1][y]=max(dp[1][y],i);
}
for(int c=0;c<=k;++c){
for(int i=0;i<(1<<k);++i){
if(dp[1][i]-dp[0][i]>=m){
printf("%d\n",k-c);
printf("%d %d",dp[0][i]+1,dp[1][i]);
return 0;
}
}
for(int i=0;i<(1<<k);++i){
tmp[i]=dp[0][i];
for(int j=0;j<k;++j){
tmp[i]=min(tmp[i],dp[0][i^(1<<j)]);
}
}
for(int i=0;i<(1<<k);++i){
dp[0][i]=tmp[i];
}
}
return 0;
}