题目
题目链接:https://codeforces.com/contest/1487/problem/G
你有 (26) 个不同的字符,第 (i) 个字符有 (c_i) 个。
你希望用这些字符,构造出一个字符串(每个字符在字符串中出现的个数不超过 (c_i)),使得这个字符串上不存在长度为奇数且大于 (1) 的回文串。求出方案数对 (998244353) 取模的结果。
(nleq 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;
}