AtCoder Beginner Contest 301 F Anti-DDoS

洛谷传送门

AtCoder 传送门

考虑分类计数,讨论“没有 DD”、“有 DDo”、“有 DDoS”三种情况。

  • 没有 DD,枚举有几种大写字母出现过;
  • 剩下两种情况,考虑设 \(f_{i,0/1}\) 分别表示两种情况的方案数。\(f_{i,0}\) 可以从 \(f_{i-1,0}\) 填大写字母转移,也可以枚举第一个出现两次的字母,然后枚举剩下出现了几个字母;\(f_{i,1}\) 可以从 \(f_{i-1,0}\)\(f_{i-1,1}\) 填小写字母转移。

时间复杂度 \(O(26^2n)\),精细实现可过。

code
// Problem: F - Anti-DDoS
// Contest: AtCoder - パナソニックグループプログラミングコンテスト2023(AtCoder Beginner Contest 301)
// URL: https://atcoder.jp/contests/abc301/tasks/abc301_f
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
#define pb emplace_back
#define fst first
#define scd second
#define mems(a, x) memset((a), (x), sizeof(a))

using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
typedef long double ldb;
typedef pair<ll, ll> pii;

const int maxn = 300100;
const ll mod = 998244353;

inline ll qpow(ll b, ll p) {
	ll res = 1;
	while (p) {
		if (p & 1) {
			res = res * b % mod;
		}
		b = b * b % mod;
		p >>= 1;
	}
	return res;
}

ll n, fac[maxn], ifac[maxn], f[maxn][2], pw[maxn], c[maxn][30], g[maxn][30];
ll h1[30][30], h2[30][30];
bool vis[128];
char s[maxn];

inline ll C(ll n, ll m) {
	if (n < m || n < 0 || m < 0) {
		return 0;
	} else {
		return fac[n] * ifac[m] % mod * ifac[n - m] % mod;
	}
}

void solve() {
	scanf("%s", s + 1);
	n = strlen(s + 1);
	fac[0] = 1;
	for (int i = 1; i <= n + 50; ++i) {
		fac[i] = fac[i - 1] * i % mod;
	}
	ifac[n + 50] = qpow(fac[n + 50], mod - 2);
	for (int i = n + 49; ~i; --i) {
		ifac[i] = ifac[i + 1] * (i + 1) % mod;
	}
	pw[0] = 1;
	for (int i = 1; i <= n; ++i) {
		pw[i] = pw[i - 1] * 26 % mod;
	}
	for (int i = 0; i <= n + 50; ++i) {
		for (int j = 0; j <= min(i, 26); ++j) {
			c[i][j] = C(i, j);
			g[i][j] = c[i][j] * pw[i - j] % mod;
		}
	}
	for (int i = 0; i <= 26; ++i) {
		for (int j = 0; j <= 26; ++j) {
			h1[i][j] = c[i][j] * fac[j] % mod;
			if (j) {
				h2[i][j] = c[i][j - 1] * fac[j - 1] % mod * j % mod;
			}
		}
	}
	bool flag = 0;
	int cnt = 0, d = 0, T = 0;
	for (int i = 1; i <= n; ++i) {
		for (int j = 0; j < 52; ++j) {
			if (s[i] != '?') {
				if (isupper(s[i]) && s[i] != 'A' + j) {
					continue;
				} else if (islower(s[i]) && s[i] != 'a' + (j - 26)) {
					continue;
				}
			}
			if (j < 26 && !flag) {
				if (vis['A' + j]) {
					int t = 26 - d;
					for (int k = 0; k <= min(26, cnt); ++k) {
						f[i][0] = (f[i][0] + g[cnt][k] * h1[t][k]) % mod;
					}
				} else if (cnt) {
					int t = 25 - d;
					for (int k = 1; k <= min(26, cnt); ++k) {
						f[i][0] = (f[i][0] + g[cnt][k] * h2[t][k]) % mod;
					}
				}
			}
			if (j < 26) {
				f[i][0] = (f[i][0] + f[i - 1][0]) % mod;
			}
			if (j >= 26) {
				f[i][1] = (f[i][1] + f[i - 1][0] + f[i - 1][1]) % mod;
			}
		}
		if (isupper(s[i]) && vis[s[i]]) {
			flag = 1;
		}
		if (isupper(s[i])) {
			vis[s[i]] = 1;
			++d;
		}
		cnt += (s[i] == '?');
	}
	ll ans = (f[n][0] + f[n][1]) % mod;
	if (!flag) {
		int k = 26 - d;
		for (int i = 0; i <= min(k, cnt); ++i) {
			ans = (ans + C(cnt, i) * pw[cnt - i] % mod * C(k, i) % mod * fac[i] % mod) % mod;
		}
	}
	printf("%lld\n", ans);
}

int main() {
	int T = 1;
	// scanf("%d", &T);
	while (T--) {
		solve();
	}
	return 0;
}

posted @ 2023-05-16 10:34  zltzlt  阅读(134)  评论(0编辑  收藏  举报