题解:P11146 「SFMOI Round I」Strange Train Game
题意
题目本身已经够简洁了,故直接搬来。
给定长度为 的 串 ,给定 个正整数 。对于 ,依次执行以下操作:
- 选择是否执行第 次操作。
- 如果执行,则对于 ,交换 。
最大化 的字典序并输出最终的结果。
分析
显然, 相同的位怎么操作都不变,可以直接丢掉。
剔除后每个操作相当于给 的一个区间异或上 ,我们只要贪心地让高位取最大就行了。
考虑部分分的情况:所有的 互不相同,显然每个操作对第 位的影响是唯一的,根据 贪心地选即可。
若存在 相同,不妨考虑最简单的情况(有被异或到的用 表示,否则用 表示):
11100
11111
这两个操作选或不选构成的 种情况分别是:
00000
11100
00011
11111
和操作 11100 和 00011 构成的结果相同!也就是说我们把 11111 改成 00011 并不影响答案!根据归纳法,这个东西可以扩展到多个的情况,如 个:
110000 <=> 110000
111000 <=> 001000
111110 <=> 000110
111111 <=> 000001
于是我们就能把 相同的情况转化为 不同的,若两个操作会变成完全一样则可以去掉一个。这道题就做完了。
代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
long long read(){
long long x=0,f=1;char ch=getchar();
while(!isdigit(ch))
{if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
return x*f;
}
void write(long long x){
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10+'0');
}
const int N=2e5+10;
int n,m,tn,tm;
string sa,sb;
struct oper{
int l,r;
}op[N];
int id[N],a[N],b[N];
int mu[N];
vector<int>adl[N];
bool cmp(int x,int y){
return op[x].r<op[y].r;
}
int main(){
//freopen(".in","r",stdin);
//freopen(".out","w",stdout);
n=read();m=read();
cin>>sa>>sb;
for(int i=1;i<=m;i++){
op[i].l=read();op[i].r=read();
}
for(int i=1;i<=n;i++){
if(sa[i-1]!=sb[i-1]){
a[++tn]=sa[i-1]-'0';
b[tn]=sb[i-1]-'0';
id[tn]=i;
}
}
for(int i=1;i<=m;i++){
if(op[i].l>id[tn]||op[i].r<id[1])continue;
op[i].l=lower_bound(id+1,id+tn+1,op[i].l)-id;
op[i].r=upper_bound(id+1,id+tn+1,op[i].r)-id-1;
if(1<=op[i].l&&op[i].l<=op[i].r&&op[i].r<=tn){
adl[op[i].l].push_back(i);
}
}
int now=0,lst=0;
for(int i=1;i<=tn;i++){
now^=mu[i];
if(adl[i].size()){
sort(adl[i].begin(),adl[i].end(),cmp);
int x=adl[i][0];
for(int j=1;j<adl[i].size();j++){
if(op[adl[i][j]].r==op[adl[i][j-1]].r)continue;
adl[op[adl[i][j-1]].r+1].push_back(adl[i][j]);
}
adl[i].clear();adl[i].push_back(x);
if(!(now^a[i])){
mu[op[x].r+1]^=1;
now^=1;
}
sa[id[i]-1]='1';
}
else{
if(now^a[i])sa[id[i]-1]='1';
else sa[id[i]-1]='0';;
}
}
cout<<sa<<endl;
return 0;
}

浙公网安备 33010602011771号