【CF1487G】String Counting

题目

题目链接:https://codeforces.com/contest/1487/problem/G

你有 \(26\) 个不同的字符,第 \(i\) 个字符有 \(c_i\) 个。
你希望用这些字符,构造出一个字符串(每个字符在字符串中出现的个数不超过 \(c_i\)),使得这个字符串上不存在长度为奇数且大于 \(1\) 的回文串。求出方案数对 \(998244353\) 取模的结果。
\(n\leq 400;\frac{n}{3} < c_i \leq n\)

思路

显然等价于不存在两个位置 \(i,i+2\) 满足 \(s_i=s_{i+2}\)
这个 \(c_i>\frac{n}{3}\) 意味着最多只有两个字符可能会超出限制,所以考虑容斥。
\(f[i][j][k][0/1/2][0/1/2]\) 表示选到第 \(i\) 个位置,字符 \(x\) 出现 \(j\) 次,\(y\) 出现 \(k\) 次,第 \(i-2,i-1\) 位置的字符分别为 除 \(x,y\) 外的字符/字符 \(x\)/字符 \(y\) 的方案数。
不用考虑字符 \(x,y\) 分别是什么,也不用考虑使用有没有超出 \(c_x,c_y\),只要求不存在两个位置 \(i,i+2\) 满足 \(s_i=s_{i+2}\)
这个东西大力分类讨论即可。注意当第 \(i\) 位填除 \(x,y\) 外的字符时,转移过来的权值可能为 \(23\)\(24\)
然后记 \(g[i][j]\) 表示字符 \(x\) 使用至少 \(i\) 个,字符 \(y\) 使用至少 \(j\) 个的方案数。直接把 \(f\) 做一遍后缀和即可。
容斥一下即可得到答案

\[g[0][0]-\sum^{26}_{i=1}g[c_i+1][0]+\sum^{26}_{i=1}\sum^{26}_{j=i+1}g[c_i+1][c_j+1] \]

\(f\) 数组滚动一下,时间复杂度 \(O(n^3)\),空间复杂度 \(O(n^2)\)

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N=210,MOD=998244353;
int n,ans,c[30],f[2][N][N][3][3],g[N][N];

signed main()
{
	scanf("%d",&n);
	for (int i=1;i<=26;i++)
		scanf("%d",&c[i]);
	f[0][0][0][0][0]=24*24;
	f[0][1][0][1][0]=f[0][1][0][0][1]=f[0][0][1][0][2]=f[0][0][1][2][0]=24;
	f[0][1][1][1][2]=f[0][1][1][2][1]=f[0][2][0][1][1]=f[0][0][2][2][2]=1;
	for (int i=3;i<=n;i++)
	{
		int id=i&1;
		memset(f[id],0,sizeof(f[id]));
		for (int j=0;j<=n/2+1;j++)
			for (int k=0;k<=n/2+1;k++)
			{
				f[id][j][k][0][0]=(23LL*f[id^1][j][k][0][0]+24LL*f[id^1][j][k][1][0]+24LL*f[id^1][j][k][2][0])%MOD;
				f[id][j][k][1][0]=(23LL*f[id^1][j][k][0][1]+24LL*f[id^1][j][k][1][1]+24LL*f[id^1][j][k][2][1])%MOD;
				f[id][j][k][2][0]=(23LL*f[id^1][j][k][0][2]+24LL*f[id^1][j][k][1][2]+24LL*f[id^1][j][k][2][2])%MOD;
				if (j) f[id][j][k][0][1]=(f[id^1][j-1][k][0][0]+f[id^1][j-1][k][2][0])%MOD;
				if (j) f[id][j][k][1][1]=(f[id^1][j-1][k][0][1]+f[id^1][j-1][k][2][1])%MOD;
				if (j) f[id][j][k][2][1]=(f[id^1][j-1][k][0][2]+f[id^1][j-1][k][2][2])%MOD;
				if (k) f[id][j][k][0][2]=(f[id^1][j][k-1][0][0]+f[id^1][j][k-1][1][0])%MOD;
				if (k) f[id][j][k][1][2]=(f[id^1][j][k-1][0][1]+f[id^1][j][k-1][1][1])%MOD;
				if (k) f[id][j][k][2][2]=(f[id^1][j][k-1][0][2]+f[id^1][j][k-1][1][2])%MOD;
			}
	}
	for (int i=n/2+1;i>=0;i--)
		for (int j=n/2+1;j>=0;j--)
		{
			ll sum=0;
			for (int k=0;k<=8;k++)
				sum=(sum+f[n&1][i][j][k/3][k%3])%MOD;
			g[i][j]=(sum+g[i+1][j]+g[i][j+1]-g[i+1][j+1])%MOD;
		}
	ans=g[0][0];
	for (int i=1;i<=26;i++)
		if (c[i]+1<N) ans=(ans-g[c[i]+1][0])%MOD;
	for (int i=1;i<=26;i++)
		for (int j=i+1;j<=26;j++)
			if (max(c[i],c[j])+1<N)
				ans=(ans+g[c[i]+1][c[j]+1])%MOD;
	printf("%d",(ans%MOD+MOD)%MOD);
	return 0;
}
posted @ 2021-05-13 14:23  stoorz  阅读(60)  评论(0编辑  收藏  举报