https://codeforces.com/contest/1290/problem/B
傻逼题想了好久,训练不饱和摸鱼太多变菜了,虽然本来构造题就很菜。
首先想到一点,对于可分割的相同字母异序词,是前面一段字母数量和种类相同,后面一段字母数量和种类相同。
那么目标就是判断一个串是否可以构造出一个不可分割的相同字母异序词,也就是从开头一直到最后,所有字母的数量种类才能相同,也就是所有前缀,都没有字母的数量种类相同的。
对于长度为1的,本身不可分割。对于s[l]!=s[r]的,如果把s[l]和s[r]交换,中间的全一样。那么可以想到从开始字母就不同,而中间又全一样,那么直到最后位置之前,字母数量种类始终不同。
进而想到如果一个串有两种字母,假设为ab,且s[l]=s[r]=a,那么我怎么排列,我仅仅只能调换两种字母的顺序,首先我必须让s[l]=b,不然s[l]就能被分割出去,这就少了1个b,那然后依次构造,由于只有两种字母,我一个字母不够了只能用另外一个字母,那么肯定会在中间的某个电放字母数量种类相同了。
那么如果一个串有3种或以上字母就好办了,假设顺序出线abca,s[l]跟b之后出线的c交换,s[r]跟第一个出线的b交换,因为现c,b顺序变化了,那么我们依次构造得时候,就只要保证所有前缀的c,b数量都不一样,就不可分割了。
#include<bits/stdc++.h>
using namespace std;
const int maxl=2e5+10;
int n,q;
int b[26][maxl];
char s[maxl];
inline void add(int i,int id,int x)
{
while(i<=n)
{
b[id][i]+=x;
i+=i&-i;
}
}
inline void prework()
{
scanf("%s",s+1);
n=strlen(s+1);
for(int i=1;i<=n;i++)
add(i,s[i]-'a',1);
}
inline int sum(int id,int i)
{
int ret=0;
while(i)
{
ret+=b[id][i];
i-=i&-i;
}
return ret;
}
inline void mainwork()
{
scanf("%d",&q);
int l,r;
for(int i=1;i<=q;i++)
{
scanf("%d%d",&l,&r);
if(s[l]!=s[r] || l==r)
{
puts("Yes");
continue;
}
int cnt=0;
for(int j=0;j<26;j++)
if(sum(j,r)-sum(j,l-1)>0)
cnt++;
if(cnt>2)
puts("Yes");
else
puts("No");
}
}
int main()
{
prework();
mainwork();
return 0;
}
本文深入解析CodeForces竞赛中一道关于字符串处理与构造算法的难题,分享了解题思路和编码实现,包括如何判断一个字符串能否构造出不可分割的相同字母异序词,以及使用差分数组进行前缀和查询的高效算法。
287

被折叠的 条评论
为什么被折叠?



