Codeforces Beta Round #17 题解

141 阅读2分钟

C. Blance

题目链接

思路

考虑将原字符串中相邻的相同字母压缩成一个得到一个新字符串称为ss',可以发现一个合法的答案经过同样的压缩后得到的字符串是ss'的一个子序列。问题就转化成求ss'不同的合法子序列的个数。

我们从原字符串入手来解决这个问题。设f[i][a][b][c]f[i][a][b][c]为只考虑前ii个字符,a,b,ca,b,c分别出现了a,b,ca,b,c次时可以得到的所有子序列的数目,考虑从当前状态会为哪些状态做出贡献。如果后面有一个字符aa位于kk,那么可以让i+1ki+1\rightarrow k都变成aa,再接上现在的字符串,此时aa的数目增加11,即当前答案会对f[k][a+1][b][c]f[k][a+1][b][c]做出贡献,以此类推。所以预处理出第ii个位置后面字母xx第一次出现的位置,DP一下就行。

代码

#include<bits/stdc++.h>
#define rep(i,st,ed) for(int i=st;i<=ed;++i)
#define bl(u,i) for(int i=head[u];i;i=e[i].nxt)
#define en puts("")
#define LLM LONG_LONG_MAX
#define LLm LONG_LONG_MIN
#define pii pair<ll,ll> 
typedef int ll;
typedef double db;
using namespace std;
const ll INF=0x3f3f3f3f;
void read() {}
void OP() {}
void op() {}
template <typename T, typename... T2>
inline void read(T &_, T2 &... oth)
{
    int __=0;
    _=0;
    char ch=getchar();
    while(!isdigit(ch))
    {
        if(ch=='-')
            __=1;
        ch=getchar();
    }
    while(isdigit(ch))
    {
        _=_*10+ch-48;
        ch=getchar();
    }
    _=__?-_:_;
    read(oth...);
}
template <typename T>
void Out(T _)
{
    if(_<0)
    {
        putchar('-');
        _=-_;
    }
    if(_>=10)
       Out(_/10);
    putchar(_%10+'0');
}
template <typename T, typename... T2>
inline void OP(T _, T2... oth)
{
	Out(_);
	putchar('\n');
	OP(oth...);
}
template <typename T, typename... T2>
inline void op(T _, T2... oth)
{
	Out(_);
	putchar(' ');
	op(oth...);
}
/*#################################*/
const ll N=155,P=51123987;
ll n,ans;
ll nxt[N][5],f[N][55][55][55];
string s;
int main()
{
	read(n);
	cin>>s;
	s=' '+s;
	for(int i=n;i>=1;--i)
	{
		rep(j,1,3)
			nxt[i][j]=nxt[i+1][j];
		nxt[i][s[i]-'a'+1]=i;
	}
	f[1][0][0][0]=1;
	ll m=(n+2)/3;
	rep(i,1,n)
		rep(a,0,m)
			rep(b,0,m)
				rep(c,0,m)
				{
					if(a+b+c==n && abs(a-b)<=1 && abs(b-c)<=1 && abs(a-c)<=1)
					{
						(ans+=f[i][a][b][c])%=P;
						continue;
					}
					rep(ch,1,3)
						if(nxt[i][ch])
							(f[nxt[i][ch]][a+(ch==1)][b+(ch==2)][c+(ch==3)]+=f[i][a][b][c])%=P;
				}
	OP(ans);
}