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;
}
posted @ 2020-09-23 22:37  gmh77  阅读(222)  评论(0编辑  收藏  举报