CF 1709F
题目大意:
对于所有长度为$1~n$的$01$串$s$, 给每个串赋值$c_s$, 我们可以确定他最大的美丽可重集
美丽可重集是一个有多个长度为$n$字符串$t$的集合, 满足所有前缀$s$出现的次数$\leq c_s$
问, $n, 0 \leq c_s \leq k$, 要使得最大美丽可重集的大小为$f$, 有多少种赋值方案
做法:
建出trie树, 那么每个节点可以唯一对应一个前缀, c可以看作从根到这个点最多有多少条路径
设dp[i][j]表示第i层的节点, 他的孩子中的最大可重集为j的方案
也就是有两种情况
- c >= k1 + k2,也就是当前节点的可重集受到孩子的限制, j = k1 + k2, 方案有$k - c$种
- c <= k1 + k2,也就是当前节点的可重集受自己的限制, 此时当做可重集受到当前节点的限制, 也就是j < k1 + k2, 求一个后缀和
综上, =号需要特殊考虑, 防止重复
可以发现这么转移满足了每一个限制, 所以j肯定是最大的可重集
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 typedef unsigned long long ull; 5 typedef pair<int,int> pii; 6 #define pb push_back 7 #define ln '\n' 8 const int mod = 998244353; 9 inline void inc(int &a, int b){ 10 a+=b; 11 if(a>=mod) a-=mod; 12 } 13 inline void dec(int &a, int b){ 14 a-=b; 15 if(a<0) a+=mod; 16 } 17 18 const int g=3; 19 inline int power(int a, int b){ 20 int res = 1; 21 for(; b; b>>=1, a=1ll*a*a%mod) 22 if(b&1) 23 res=1ll*res*a%mod; 24 return res; 25 } 26 27 void ntt(int *a, int n, int flag){ 28 for(int i=(n>>1), j=1; j<n; j++){ 29 if(i<j) swap(a[i], a[j]); 30 int k = (n>>1); 31 while(i&k){i^=k; k>>=1;} 32 i^=k; 33 } 34 for(int k=2; k<=n; k<<=1){ 35 int rt = power(g, (mod-1)/k); 36 if(flag == -1) 37 rt = power(rt, mod-2); 38 for(int i=0; i<n; i+=k){ 39 int del = 1; 40 for(int j=i; j<i+k/2; j++){ 41 int u = a[j], v = 1ll * del * a[j+k/2] % mod; 42 a[j] = (u + v) % mod; 43 a[j+k/2] = (u - v + mod) % mod; 44 del = 1ll * del * rt % mod; 45 } 46 } 47 } 48 if(flag == -1){ 49 int inv = power(n, mod-2); 50 for(int i=0; i<n; i++) 51 a[i] = 1ll * a[i] * inv % mod; 52 } 53 } 54 //空间记得开两倍两倍两倍 55 void mul(int *a, int n){ 56 int m; 57 for(m = n<<1, n=1; n<=m; n<<=1); 58 ntt(a, n, 1); 59 for(int i=0; i<n; i++) 60 a[i] = 1ll * a[i] * a[i] % mod; 61 ntt(a, n, -1); 62 } 63 64 const int N = 1<<19; 65 int dp[20][N]; 66 int tmp[N]; 67 68 int main(){ 69 ios::sync_with_stdio(false); 70 cin.tie(0); 71 int n, k, f; 72 cin >> n >> k >> f; 73 for(int i=0; i<=k; i++) 74 dp[n][i] = 1; 75 76 for(int i=n-1; i; i--){ 77 mul(dp[i+1], k); 78 for(int j=k+k, sum = 0; j>=0; j--){ 79 inc(sum, dp[i+1][j]); 80 if(j <= k) 81 dp[i][j] = (1ll * dp[i+1][j] * (k-j) % mod + sum)%mod; 82 } 83 } 84 85 // for(int i=0; i<=(k<<1); i++) 86 // cout << dp[1][i] << " "; 87 mul(dp[1], k); 88 cout << dp[1][f] << ln; 89 }