题解:CF2048C Kevin and Binary Strings
· 阅读需 2 分钟
原题链接
题意简述
给定一个以 开头的 字符串 ,选取两个子串,使得它们 的异或和最大。
解题思路
设字符串 的长度为 ,并定义字符串 为字符串 的按位取反。
显然,第一个子串应选取整个字符串 ,因为只有这样才能保证第一个位置的 在异或操作中发挥最大作用。
接下来的目标是让第二个子串的异或结果尽可能大。为了实现这一点,我们需要找到最右边的一个 ,设其位置为 。为了最大化异或结果,我们要将这个 变为 ,因此我们需要选择一个以 开头、长度为 的子串。
将第二个子串的选择转化为在字符串 中匹配字符串 。如果能够找到匹配的子串,则继续向右进行匹配,直到无法再找到合适的匹配为止。在每次匹配时,右边的部分也要尽量变为 ,即在 匹配 ,依此类推。
参考代码
#include <bits/stdc++.h>
using namespace std;
using ll=long long;
const int N=5005;
int nxt[N];
int kmp(string s,string t)
{
int n=s.size(),m=t.size();
for(int i=1;i<m;i++)
{
int j=nxt[i-1];
while(j&&t[i]!=t[j])j=nxt[j-1];
if(t[i]==t[j])j++;
nxt[i]=j;
}
int j=0;
for(int i=0;i<n;i++)
{
while(j&&s[i]!=t[j])j=nxt[j-1];
if(s[i]==t[j])j++;
if(j==m)return i-m+1;
}
return -1;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T;
cin>>T;
while(T--)
{
string s;
cin>>s;
int n=s.size(),m=n-1;
string t=s;
for(int i=n-1;i>=0;i--)
{
t[i]='0'+'1'-t[i];
if(s[i]=='0')m=i;
}
int x=0;
for(int i=m;i<n;i++)
{
int k=kmp(t.substr(0,i),s.substr(m,i-m+1));
if(k==-1)break;
x=k;
}
cout<<1<<' '<<n<<' '<<x+1<<' '<<x+n-m<<'\n';
}
return 0;
}