「杂题乱刷2」CF2069D
题目链接
CF2069D(*1900) Palindrome Shuffle(luogu)
CF2069D(*1900) Palindrome Shuffle(codeforces)
解题思路
本文 \(V\) 代表 \(26\),即字符集大小。
这题是史,大家一起吃。
首先根据题中定义这题显然长度为 \(i(i < n)\) 合法,则长度为 \(i + 1\) 合法,因为你可以任意交换,不影响。
因此此题可以二分答案。
那么容易得出 check 一个长度 \(len\) 是否合法只需要判断是否有至少一个长度为 \(len\) 的区间合法即可,那么我们考虑如何进行 check 一个任意交换区间 \([l,r]\) 是否合法,首先通过提前预处理判断掉不能任意交换且字母本应该相同的位置是否合法,处理完这个之后此时我们可以考虑分讨以下几种情况:
-
\(r \le \displaystyle \frac{n}{2}\),此时整个可交换的区间都在左边,只需要前缀和即可 \(O(V)\) 判断一个区间是否合法。
-
\(l > \displaystyle \frac{n}{2}\),此时整个可交换的区间都在右边,只需要前缀和即可 \(O(V)\) 判断一个区间是否合法。
-
\(l \le \displaystyle \frac{n}{2} < r\),则此时可交换区间包含左右两边,此时我们继续分讨:
-
\(\displaystyle\frac{n}{2} - l < r - \displaystyle\frac{n}{2}\),此时我们只需要判断左边是否能暴力匹配右边的字母即可。
-
\(\displaystyle\frac{n}{2} - l \ge r - \displaystyle\frac{n}{2}\),此时我们只需要判断右边是否能暴力匹配左边的字母即可。
-
那么 check 就做完了,那么整题也就做完了,最后是一个二分板子,不赘述。
时间复杂度 \(O(nV \log n)\),可以通过本题。
参考代码
string s;
ll n;
ll pre[200010];
ll sum[200010][30];
ll now[30];
bool PRE(ll len){
return pre[len]==len;
}
bool ck(ll l,ll r)
{
if(l==1 && r==n)
return 1;
ll l1,l2,r1,r2;
l1=1,r1=l-1;
l2=r+1,r2=n;
ll len=min(r1,n-l2+1);
if(!PRE(len))
return 0;
if(l+r==n+1)
return 1;
forl(i,0,25)
now[i]=sum[r][i]-sum[l-1][i];
if(l<=n/2 && r<=n/2)
{
if(r!=n/2 && pre[n/2]-pre[r]!=n/2-r)
return 0;
forl(i,0,25)
if(now[i]!=sum[n+1-l][i]-sum[n+1-r-1][i])
return 0;
return 1;
}
else if(l>n/2 && r>n/2)
{
if(l!=n/2+1 && pre[n/2]-pre[n+1-l]!=n/2-(n+1-l))
return 0;
forl(i,0,25)
if(now[i]!=sum[n+1-l][i]-sum[n+1-r-1][i])
return 0;
return 1;
}
else
{
if(n/2-l<r-n/2)
{
// bug2;
forl(i,0,25)
{
now[i]-=sum[n+1-(n+1-l)-1][i]-sum[n+1-r-1][i];
if(now[i]<0)
return 0;
}
/*
r,r-1,n-l
*/
///////
// while(l+r>n+1)
// {
// //r--;
// // cout<<s[n+1-r]<<endl;
// if(!now[s[n+1-r]-'a']--)
// return 0;
// r--;
// }
// bug3;
forl(i,0,25)
if(now[i]&1)
return 0;
return 1;
}
else
{
forl(i,0,25)
{
now[i]-=sum[n+1-l][i]-sum[n+1-(n+1-r)][i];
if(now[i]<0)
return 0;
}
// bug1;
// while(l+r<n+1)
// {
// //l++;
// if(!now[s[n+1-l]-'a']--)
// return 0;
// l++;
// }
// bug4;
forl(i,0,25)
if(now[i]&1)
return 0;
return 1;
}
}
}
bool check(ll Mid)
{
forl(i,1,n-Mid+1)
if(ck(i,i+Mid-1))
return 1;
return 0;
}
ll L,R;
/*
ababa babababab
ababa babb ababa
*/
void _clear(){}
void solve()
{
_clear();
cin>>s;
n=s.size();
s=' '+s;
forl(i,1,n)
{
forl(j,0,25)
sum[i][j]=sum[i-1][j];
sum[i][s[i]-'a']++;
}
forl(i,1,n)
pre[i]=0;
forl(i,1,n/2)
pre[i]=(s[i]==s[n-i+1]);
forl(i,1,n/2)
pre[i]+=pre[i-1];
if(pre[n/2]==n/2)
{
cout<<0<<endl;
return ;
}
// cout<<ck(5,10)<<endl;
// return ;
L=1,R=n;
while(L<R)
{
ll Mid=(L+R)/2;
if(check(Mid))
R=Mid;
else
L=Mid+1;
}
cout<<L<<endl;
}

浙公网安备 33010602011771号