博客园 首页 私信博主 显示目录 隐藏目录 管理 动画

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的方案

  也就是有两种情况

    1. c >= k1 + k2,也就是当前节点的可重集受到孩子的限制, j = k1 + k2, 方案有$k - c$种
    2. 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 }
View Code

 

posted @ 2022-07-22 16:49  gllonkxc  阅读(48)  评论(0编辑  收藏  举报