正题
题目链接:https://atcoder.jp/contests/arc132/tasks/arc132_d
题目大意
给出两个恰好有nnn个111和mmm个000的字符串s,ts,ts,t,定义两个字符串距离为通过交换两个相邻的字符把一个变成另一个的最小步数。
对于字符串kkk如果dis(s,k)+dis(k,t)=dis(s,t)dis(s,k)+dis(k,t)=dis(s,t)dis(s,k)+dis(k,t)=dis(s,t)那么kkk在s,ts,ts,t之间。
定义一个字符串的权值为相邻的相同字符对数。
求所有在s,ts,ts,t之间的字符串中权值最大是多少。
1≤n+m≤3×1051\leq n+m\leq 3\times 10^51≤n+m≤3×105
解题思路
先考虑在s,ts,ts,t之间的字符串有什么性质,显然的我们对于求dis(s,t)dis(s,t)dis(s,t)的时候最优的策略肯定是把sss的第iii个111移动到ttt的第iii个111处。
也就是对于两个串中第iii个111的位置记为x,yx,yx,y,那么就是一个一要从x→yx\rightarrow yx→y,也就是在s∼ts\sim ts∼t之间的字符串第iii个一肯定在x∼yx\sim yx∼y这个范围。
这样我们处理出每个111的合法区间li,ril_i,r_ili,ri,显然的lil_ili和rir_iri必定递增,因为交换两个111的顺序必定不划算。所以可以考虑贪心。
不考虑边界的问题,那么我们显然要让111的连续段尽量少,那么从小到大考虑l,rl,rl,r如果能和上一个放一起就放一起,不然就放在rrr的位置最赚。
然后考虑边界,右边界可以直接判断因为我们肯定是尽量往右放的。左边界的话我们如果l1=1l_1=1l1=1我们就分两种情况考虑,也就是第一个放在左边界和第一个放在r1r_1r1两种情况取个最大值。
时间复杂度:O(n+m)O(n+m)O(n+m)
code
#include<cstdio>
#include<cstring>
#include<algorithm>
#define lowbit(x) (x&-x)
using namespace std;
const int N=6e5+10;
int A,B,m,n,t[N],l[N],r[N],ans,prt;
char a[N],b[N];
//void Change(int x,int val){
// while(x<=m){
// t[x]+=val;
// x+=lowbit(x);
// }
// return;
//}
//int Ask(int x){
// int ans=0;
// while(x){
// ans+=t[x];
// x-=lowbit(x);
// }
// return ans;
//}
int main()
{scanf("%d%d",&A,&B);m=A+B;scanf("%s",a+1);scanf("%s",b+1);for(int i=1;i<=m;i++)if(a[i]=='1')l[++n]=i;n=0;for(int i=1;i<=m;i++)if(b[i]=='1')r[++n]=i;for(int i=1;i<=n;i++){if(l[i]>r[i])swap(l[i],r[i]);}int last=-1;for(int i=1;i<=n;i++){if(l[i]<=last+1)last++;else ans++,last=r[i];}ans=ans*2;if(last!=m)ans++;prt=m-ans;if(l[1]==1){last=1;ans=1;for(int i=2;i<=n;i++){if(l[i]<=last+1)last++;else ans+=2,last=r[i];}if(last!=m)ans++;ans=m-ans;prt=max(prt,ans);}printf("%d\n",prt);return 0;
}