题意
你需要构造一个长度为 N N N的字符串,每个字符串最多含某个字符 c i c_i ci,问能构造多少个不含奇回文串的字符串。
N ≤ 400 , N 3 < c i ≤ N N\leq 400,\frac{N}{3} < c_i \leq N N≤400,3N<ci≤N
分析
考虑
c
i
c_i
ci有下界,所以至多两个字符会超过上界。
没有奇回文,就是说串中
s
i
s_i
si 和
s
i
−
2
s_{i-2}
si−2 不相同,考虑如果是所有字符都没有上限的话,就是前两个字符有26种填法,后面都是25种填法。
根据性质,考虑容斥:
答 案 = 总 的 方 案 数 − 至 少 1 个 超 过 上 限 + 至 少 2 个 超 过 上 限 答案= 总的方案数 - 至少1个超过上限 + 至少2个超过上限 答案=总的方案数−至少1个超过上限+至少2个超过上限
发现是什么字符其实不这么重要,主要是数量。
定义 f [ i ] [ j ] [ k ] [ l ] [ p ] f[i][j][k][l][p] f[i][j][k][l][p] 表示已经完成了串中的前i个位置,用了j个上限1字符,k个上限2字符,i-2位的状态是l,i-1位的状态是p
最后累计一个后缀和就好了
代码
#include <bits/stdc++.h>
using namespace std;
template <int MOD_> struct modnum {
static constexpr int MOD = MOD_;
static_assert(MOD_ > 0, "MOD must be positive");
private :
using ll = long long;
int v;
static int minv(int a,int m) {
a %= m;
assert(a);
return a == 1 ? 1 : int(m - ll(minv(m,a)) * ll(m) / a);
}
public :
modnum() : v(0) {}
modnum(int v_) : v((v_%MOD+MOD)%MOD) {}
modnum(long long v_) : v(static_cast<int>((v_%MOD+MOD)%MOD)) {}
explicit operator int() const { return v; }
friend std::ostream& operator << (std::ostream& out,const modnum& n) { return out << int(n); }
friend std::istream& operator >> (std::istream& in,modnum& n) { ll v_; in >> v_; n = modnum(v_); return in; }
bool operator ! () const { return !(*this); }
bool operator < (const modnum& b) const { return v < b.v; }
bool operator > (const modnum& b) const { return v > b.v; }
bool operator == (const modnum& b) const { return v == b.v; }
bool operator != (const modnum& b) const { return v != b.v; }
bool operator <= (const modnum& b) const { return v < b.v || v == b.v; }
bool operator >= (const modnum& b) const { return v > b.v || v == b.v; }
modnum& operator += (const modnum& b) {
v += b.v;
if(v >= MOD) v -= MOD;
return *this;
}
modnum& operator -= (const modnum& b) {
v -= b.v;
if(v < 0) v += MOD;
return *this;
}
modnum& operator *= (const modnum& b) {
v = int(ll(v) * ll(b.v) % MOD);
return *this;
}
modnum& operator /= (const modnum& b) {
return *this *= b.inv();
}
modnum inv() const {
modnum res;
res.v = minv(v , MOD);
return res;
}
friend modnum operator ++ (modnum& a, int){ modnum r = a; ++a; return r;}
friend modnum operator -- (modnum& a, int){ modnum r = a; --a; return r;}
friend modnum operator + (const modnum& a,const modnum& b){ return modnum(a) += b;}
friend modnum operator - (const modnum& a,const modnum& b){ return modnum(a) -= b;}
friend modnum operator * (const modnum& a,const modnum& b){ return modnum(a) *= b;}
friend modnum operator / (const modnum& a,const modnum& b){ return modnum(a) /= b;}
};
using Mint = modnum<998244353>;
const int Mod = 998244353;
Mint dp[2][410][410][3][3],sum[410][410];
int n,c[410];
signed main() {
ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
cin >> n;
for(int i=1;i<=26;++i) cin >> c[i];
memset(dp,0,sizeof(dp));
int op = 0; dp[op][0][0][0][0] = 1;
for(int i=1;i<=n;++i,op^=1) {
memset(dp[op^1],0,sizeof(dp[op^1]));
for(int j=0;j<i;++j) {
for(int k=0;k<i-j;++k) {
for(int p=0;p<3;p++) {
dp[op^1][j+1][k][p][1] += dp[op][j][k][0][p] + dp[op][j][k][2][p];
dp[op^1][j][k+1][p][2] += dp[op][j][k][0][p] + dp[op][j][k][1][p];
dp[op^1][j][k][p][0] += (dp[op][j][k][1][p] + dp[op][j][k][2][p]) * Mint(24);
dp[op^1][j][k][p][0] += dp[op][j][k][0][p] * (i>2 ? Mint(23) : Mint(24));
}
}
}
}
for(int j=0;j<=n;j++) for(int k=0;k<=n;k++) {
for(int p=0;p<3;p++) for(int l=0;l<3;l++) {
sum[j][k] += dp[op][j][k][p][l];
}
}
for(int j=n;j>=0;j--) for(int k=n;k>=0;k--) {
sum[j][k] += sum[j+1][k] + sum[j][k+1] - sum[j+1][k+1];
}
Mint ans = 26; for(int i=1;i<n;i++) {
if(i == 1) ans = ans * Mint(26);
else ans = ans * Mint(25);
}
for(int i=1;i<=26;i++) ans = ans - sum[c[i]+1][0];
for(int i=1;i<=26;i++) for(int j=i+1;j<=26;j++) ans = ans + sum[c[i]+1][c[j]+1];
cout << ans << endl;
}