agc027E - ABBreviate
题目大意
题解
长的有点像agc030E实际上没有任何关系,仔细地xjb玩了一两天
正难则反,考虑一个串每次把a->bb,b->aa能变成什么,把相同长度的分为一层
a->bb
b->aa
aa->bba,abb
ab->aaa,bbb
ba->aaa,bbb
bb->aab,baa
……
首先可以归纳得到一个结论:一个非ab交替的串通过操作一定可以变成a,b,ab,ba四个中的某几个
然后根据观察可以发现,把a看作+1b看作-1,一个串在操作过程中的值模3不变
进一步观察可以发现,一个串最后变成什么取决于它的值,为0是ab,ba,为1是a,为2是b
考虑如何判定一个串T,把T的每个字母扩展成一个串,把这些串拼成S,如果能拼出来则可以,注意一个字母不能扩展成ab交替串
想过把a->bb之后再扩展,但实际上扩展出来的两个串合在一起可以用b来表示,所以没有必要
那么考虑如何计数,设f[i]表示S[1,i]的答案,枚举j满足[j+1,i]的值等于枚举放的字母,并且不是ab交替
这样显然会算重,也显然的可以根据套路只从后往前第一个满足的转移
有一些思考:当j,k(j<k)都能转移到i时,[j+1,k]的值为0
转移的前提条件时f[j]是f[k]的子集,但如果[j+1,k]是ab交替串怎么办?
可以发现每次接上去的串值≠0,因此j不会直接更新到k,而是存在x->j,y->k,手玩一下可以发现x->k是可以的并且等价与x->j且[x+1,y]不是ab交替串,所以直接k->i
但是有特殊情况,当S串的头是ab交替的时候不满足上面的,即应该从[1,i-1]->i,特判一下即可
用辅助数组转移即可做到O(n)
code
#include <bits/stdc++.h>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define add(a,b) a=((a)+(b))%1000000007
#define mod 1000000007
#define ll long long
//#define file
using namespace std;
int b[100001],c[100001],n,i,j,k,l,ls;
char a[100002];
ll f[100001],g[100001],F[100001][3];
int main()
{
#ifdef file
freopen("agc027e.in","r",stdin);
#endif
scanf("%s",a+1),n=strlen(a+1);
fo(i,1,n) b[i]=(b[i-1]+((a[i]=='a')?1:-1)+3)%3,c[i]=c[i-1]+(a[i]!=a[i+1]);
ls=0;
fo(i,1,n)
{
fo(j,0,2) F[i][j]=F[i-1][j];
if (a[i-1]==a[i]) ls=i-1;
if (i>1 && (b[i-1]+1)%3==b[i]) add(f[i],g[i-1]);
else
add(f[i],F[ls][(b[i]+2)%3]);
if (b[i]==1 && (c[i-1]!=i-1 || i==1)) add(f[i],1);
if (i>1 && (b[i-1]+2)%3==b[i]) add(f[i],g[i-1]);
else
add(f[i],F[ls][(b[i]+1)%3]);
if (b[i]==2 && (c[i-1]!=i-1 || i==1)) add(f[i],1);
if (c[i-1]==i-1) g[i]=(i+1)/2,f[i]=1; else g[i]=f[i];
F[i][b[i]]=g[i];
}
printf("%lld\n",f[n]);
fclose(stdin);
fclose(stdout);
return 0;
}