CTS2019 题解

随机立方体

设$f_i$为恰有$i$个极大值的概率,$g_i$为至少有$i$个极大值的概率。

先求方案数,考虑组合意义,第$i$大的数相当于要是$nml-(n-k+i-1)(m-k+i-1)(l-k+i-1)$个数(包括它直接控制和被比它小的的极大值控制的)中最大的,那么设$h_i$为选$i$个极大值的方案数,则

$$h_i=\prod_{j=0}^{i-1}(n-j)(m-j)(l-j)$$

$$g_i=h_i\prod_{j=1}^i\frac{1}{nml-(n-i+j-1)(m-i+j-1)(l-i+j-1)}$$

$$g_i=\sum_{j=i}^n\binom{j}{i}f_j$$

二项式反演即可,注意线性求逆元。

注意代码里的变量名意义和上面并不一样。

  1 #include <bits/stdc++.h>
  2 
  3 #define IL __inline__ __attribute__((always_inline))
  4 
  5 #define For(i, a, b) for (int i = (a), i##end = (b); i <= i##end; ++ i)
  6 #define FOR(i, a, b) for (int i = (a), i##end = (b); i < i##end; ++ i)
  7 #define Rep(i, a, b) for (int i = (a), i##end = (b); i >= i##end; -- i)
  8 #define REP(i, a, b) for (int i = (a) - 1, i##end = (b); i >= i##end; -- i)
  9 
 10 typedef long long LL;
 11 
 12 template <class T>
 13 IL bool chkmax(T &a, const T &b) {
 14   return a < b ? ((a = b), 1) : 0;
 15 }
 16 
 17 template <class T>
 18 IL bool chkmin(T &a, const T &b) {
 19   return a > b ? ((a = b), 1) : 0;
 20 }
 21 
 22 template <class T>
 23 IL T mymax(const T &a, const T &b) {
 24   return a > b ? a : b;
 25 }
 26 
 27 template <class T>
 28 IL T mymin(const T &a, const T &b) {
 29   return a < b ? a : b;
 30 }
 31 
 32 template <class T>
 33 IL T myabs(const T &a) {
 34   return a > 0 ? a : -a;
 35 }
 36 
 37 const int INF = 0X3F3F3F3F;
 38 const double EPS = 1E-8, PI = acos(-1.0);
 39 
 40 #define DEBUG(...) fprintf(stderr, __VA_ARGS__)
 41 #define OK DEBUG("Passing [%s] in LINE %d...\n", __FUNCTION__, __LINE__)
 42 
 43 const int MAXN = 5000000 + 5;
 44 
 45 namespace Math {
 46 const int MOD = 998244353;
 47 
 48 IL int add(int a, int b) {
 49   a += b;
 50   return a >= MOD ? a - MOD : a;
 51 }
 52 
 53 template <class ...Args>
 54 IL int add(int a, const Args &...args) {
 55   a += add(args...);
 56   return a >= MOD ? a - MOD : a;
 57 }
 58 
 59 IL int sub(int a, int b) {
 60   a -= b;
 61   return a < 0 ? a + MOD : a;
 62 }
 63 
 64 IL int mul(int a, int b) {
 65   return (LL)a * b % MOD;
 66 }
 67 
 68 template <class ...Args>
 69 IL int mul(int a, const Args &...args) {
 70   return (LL)a * mul(args...) % MOD;
 71 }
 72 
 73 IL int quickPow(int a, int p) {
 74   int result = 1;
 75   for (; p; p >>= 1, a = mul(a, a)) {
 76     if (p & 1) {
 77       result = mul(result, a);
 78     }
 79   }
 80   return result;
 81 }
 82 }
 83 
 84 using namespace Math;
 85 
 86 int f[MAXN], g[MAXN], inv_g[MAXN], fac[MAXN], ifac[MAXN];
 87 
 88 IL void init(int n) {
 89   fac[0] = 1;
 90   For(i, 1, n) {
 91     fac[i] = mul(fac[i - 1], i);
 92   }
 93   ifac[n] = quickPow(fac[n], MOD - 2);
 94   REP(i, n, 0) {
 95     ifac[i] = mul(ifac[i + 1], i + 1);
 96   }
 97 }
 98 
 99 IL int binom(int n, int m) {
100   return mul(fac[n], ifac[m], ifac[n - m]);
101 }
102 
103 int main() {
104   int T;
105   scanf("%d", &T);
106   while (T --) {
107     int n, m, l, k;
108     scanf("%d%d%d%d", &n, &m, &l, &k);
109     int mult = mul(n, m, l), min = mymin(n, mymin(m, l));
110     init(min);
111     int cur = 1;
112     f[0] = 1;
113     For(i, 1, min) {
114       f[i] = mul(f[i - 1], n - i + 1, m - i + 1, l - i + 1);
115       g[i] = sub(mult, mul(n - i, m - i, l - i));
116       cur = mul(cur, g[i]);
117     }
118     inv_g[min] = quickPow(cur, MOD - 2);
119     REP(i, min, 0) {
120       inv_g[i] = mul(inv_g[i + 1], g[i + 1]);
121     }
122     int answer = 0;
123     cur = 1;
124     For(i, k, min) {
125       answer = add(answer, mul(cur, f[i], inv_g[i], binom(i, k)));
126       cur = mul(cur, MOD - 1);
127     }
128     printf("%d\n", answer);
129   }
130   return 0;
131 }
View Code

 珍珠

考虑同一个权值至多贡献一个奇数,那么至多有$n-2m$个权值出现奇数次。

一个权值出现偶数次的EGF是$\frac{e^x+e^{-x}}{2}$,出现奇数次的EGF是$\frac{e^x-e^{-x}}{2}$。

那么答案就是

$$n!\sum_{i=0}^{n-2m}(\frac{e^x+e^{-x}}{2}+y\frac{e^x-e^{-x}}{2})^D[x^n][y^i]$$

$$n!\frac{1}{2^D}\sum_{i=0}^{n-2m}((1+y)e^x+(1-y)e^{-x})^D[x^n][y^i]$$

对内层二项式定理展开,则有

$$n!\frac{1}{2^D}\sum_{i=0}^{n-2m}\sum_{j=0}^D\binom{D}{j}e^{(2j-D)x}(1+y)^j(1-y)^{D-j}[x^n][y^i]$$

化开$e^{kx}$,即:

$$\frac{1}{2^D}\sum_{j=0}^D\binom{D}{j}(2j-D)^n\sum_{i=0}^{n-2m}(1+y)^j(1-y)^{D-j}[y^i]$$

接下来是一些神仙内容:

令$F(j,D)=\sum_{i=0}^{n-2m}(1+y)^j(1-y)^{D-j}[y^i]$,则

$$\begin{aligned}F(j,D)&=\sum_{i=0}^{n-2m}(1+y)^j(1-y)^{D-j}[y^i]\\&=\sum_{i=0}^{n-2m}(1+y)^{j-1}(-(1-y)+2)(1-y)^{D-j}[y^i]\\&=-\sum_{i=0}^{n-2m}(1+y)^{j-1}(1-y)^{D-j+1}[y^i]+2\sum_{i=0}^{n-2m}(1+y)^{j-1}(1-y)^{D-j}[y^i]\\&=-F(j-1,D)+2F(j-1,D-1)\end{aligned}$$

因为$F(0,D)$是好求的:

$$\begin{aligned}F(0,D)&=\sum_{i=0}^{n-2m}(1-y)^D[y^i]\\&=\sum_{i=0}^{n-2m}\binom{D}{i}(-1)^i\\&=\sum_{i=0}^{n-2m}\binom{D-1}{i}(-1)^i-\sum_{i=0}^{n-2m-1}\binom{D-1}{i}(-1)^i\\&=\binom{D-1}{n-2m}(-1)^{n-2m}\end{aligned}$$

那么考虑组合意义,相当于你可以从$(0,k)$走到$(j,D)$,每一步要么向右上走,贡献2,要么向正右方走,贡献-1,那么:

$$F(j,D)=\sum_{k=0}^{D}\binom{j}{D-k}2^{D-k}(-1)^{j-D+k}F(0,k)$$

然后再拆一下:

$$\begin{aligned}\text{answer}&=\frac{1}{2^D}\sum_{j=0}^D\binom{D}{j}(2j-D)^nF(j,D)\\&=\frac{1}{2^D}\sum_{j=0}^D\binom{D}{j}(2j-D)^n\sum_{k=0}^{D}\binom{j}{D-k}2^{D-k}(-1)^{j-D+k}F(0,k)\\&=\frac{D!}{2^D}\sum_{j=0}^D\sum_{k=0}^{D}\frac{1}{(D-j)!(D-k)!(j-D+k)!}(2j-D)^n2^{D-k}(-1)^{j-D+k}F(0,k)\\&=\frac{D!}{2^D}\sum_{j=0}^D\sum_{k=0}^{D}\frac{(-1)^{j+k-D}}{(j+k-D)!}\cdot\frac{(2j-D)^n}{(D-j)!}\cdot\frac{2^{D-k}F(0,k)}{(D-k)!}\end{aligned}$$

就可以卷积了。

注意一些特判。

  1 #include <bits/stdc++.h>
  2 
  3 #define IL __inline__ __attribute__((always_inline))
  4 
  5 #define For(i, a, b) for (int i = (a), i##end = (b); i <= i##end; ++ i)
  6 #define FOR(i, a, b) for (int i = (a), i##end = (b); i < i##end; ++ i)
  7 #define Rep(i, a, b) for (int i = (a), i##end = (b); i >= i##end; -- i)
  8 #define REP(i, a, b) for (int i = (a) - 1, i##end = (b); i >= i##end; -- i)
  9 
 10 typedef long long LL;
 11 
 12 template <class T>
 13 IL bool chkmax(T &a, const T &b) {
 14   return a < b ? ((a = b), 1) : 0;
 15 }
 16 
 17 template <class T>
 18 IL bool chkmin(T &a, const T &b) {
 19   return a > b ? ((a = b), 1) : 0;
 20 }
 21 
 22 template <class T>
 23 IL T mymax(const T &a, const T &b) {
 24   return a > b ? a : b;
 25 }
 26 
 27 template <class T>
 28 IL T mymin(const T &a, const T &b) {
 29   return a < b ? a : b;
 30 }
 31 
 32 template <class T>
 33 IL T myabs(const T &a) {
 34   return a > 0 ? a : -a;
 35 }
 36 
 37 const int INF = 0X3F3F3F3F;
 38 const double EPS = 1E-8, PI = acos(-1.0);
 39 
 40 #define DEBUG(...) fprintf(stderr, __VA_ARGS__)
 41 #define OK DEBUG("Passing [%s] in LINE %d...\n", __FUNCTION__, __LINE__)
 42 
 43 const int MAXN = 100000 + 5;
 44 
 45 namespace Math {
 46 const int MOD = 998244353;
 47 
 48 IL int add(int a, int b) {
 49   a += b;
 50   return a >= MOD ? a - MOD : a;
 51 }
 52 
 53 template <class ...Args>
 54 IL int add(int a, const Args &...args) {
 55   a += add(args...);
 56   return a >= MOD ? a - MOD : a;
 57 }
 58 
 59 IL int sub(int a, int b) {
 60   a -= b;
 61   return a < 0 ? a + MOD : a;
 62 }
 63 
 64 IL int mul(int a, int b) {
 65   return (LL)a * b % MOD;
 66 }
 67 
 68 template <class ...Args>
 69 IL int mul(int a, const Args &...args) {
 70   return (LL)a * mul(args...) % MOD;
 71 }
 72 
 73 IL int quickPow(int a, int p) {
 74   int result = 1;
 75   for (; p; p >>= 1, a = mul(a, a)) {
 76     if (p & 1) {
 77       result = mul(result, a);
 78     }
 79   }
 80   return result;
 81 }
 82 }
 83 
 84 using namespace Math;
 85 
 86 int fac[MAXN], ifac[MAXN];
 87 
 88 IL void init(int n) {
 89   fac[0] = 1;
 90   For(i, 1, n) {
 91     fac[i] = mul(fac[i - 1], i);
 92   }
 93   ifac[n] = quickPow(fac[n], MOD - 2);
 94   REP(i, n, 0) {
 95     ifac[i] = mul(ifac[i + 1], i + 1);
 96   }
 97 }
 98 
 99 IL int binom(int n, int m) {
100   return n >= m ? mul(fac[n], ifac[m], ifac[n - m]) : 0;
101 }
102 
103 namespace Poly {
104 const int G = 3, G_inv = (MOD + 1) / G, MASK = 18;
105 
106 int pos[1 << MASK], root[1 << MASK], root_inv[1 << MASK], len;
107 
108 IL void init(int n) {
109   for (; 1 << len <= n; ++ len);
110   FOR(i, 0, 1 << len) {
111     pos[i] = (pos[i >> 1] >> 1) | ((i & 1) << (len - 1));
112   }
113   int w = quickPow(G, (MOD - 1) >> len);
114   root[0] = 1;
115   FOR(i, 1, 1 << len) {
116     root[i] = mul(root[i - 1], w);
117   }
118   w = quickPow(G_inv, (MOD - 1) >> len);
119   root_inv[0] = 1;
120   FOR(i, 1, 1 << len) {
121     root_inv[i] = mul(root_inv[i - 1], w);
122   }
123 }
124 
125 IL void NTT(int *a, int n, int *root) {
126   int shift = __builtin_ctz((1 << len) / n);
127   FOR(i, 0, n) {
128     if (i < pos[i] >> shift) {
129       std::swap(a[i], a[pos[i] >> shift]);
130     }
131   }
132   for (int i = 2; i <= n; i <<= 1) {
133     shift = __builtin_ctz((1 << len) / i);
134     int w = i >> 1;
135     for (int *p = a; p != a + n; p += i) {
136       FOR(j, 0, w) {
137         int x = mul(p[j + w], root[j << shift]);
138         p[j + w] = sub(p[j], x);
139         p[j] = add(p[j], x);
140       }
141     }
142   }
143 }
144 
145 IL void DFT(int *a, int n) {
146   NTT(a, n, root);
147 }
148 
149 IL void IDFT(int *a, int n) {
150   NTT(a, n, root_inv);
151   int inv = quickPow(n, MOD - 2);
152   FOR(i, 0, n) {
153     a[i] = mul(a[i], inv);
154   }
155 }
156 
157 IL void multiply(int *f, int n, int *g, int m, int *result) {
158   int len = 0;
159   for (; 1 << len < n + m; ++ len);
160   static int x[1 << MASK], y[1 << MASK];
161   std::copy(f, f + n, x);
162   memset(x + n, 0, sizeof(int) * ((1 << len) - n));
163   std::copy(g, g + m, y);
164   memset(y + m, 0, sizeof(int) * ((1 << len) - m));
165   memset(result, 0, sizeof(int) << len);
166   DFT(x, 1 << len);
167   DFT(y, 1 << len);
168   FOR(i, 0, 1 << len) {
169     result[i] = mul(x[i], y[i]);
170   }
171   IDFT(result, 1 << len);
172 }
173 }
174 
175 int f[MAXN * 4], g[MAXN * 4], h[MAXN * 4];
176 
177 int main() {
178   int D, n, m;
179   scanf("%d%d%d", &D, &n, &m);
180   if (n < m * 2) {
181     puts("0");
182     exit(0);
183   }
184   if (m * 2 + D - ((D & 1) ^ (n & 1)) <= n) {
185     printf("%d\n", quickPow(D, n));
186     exit(0);
187   }
188   init(D);
189   Poly::init(D << 1);
190   auto F = [&](int k) {
191     return k ? mul((n - m * 2) % 2 ? MOD - 1 : 1, binom(k - 1, n - m * 2)) : 1;
192   };
193   For(i, 0, D) {
194     f[i] = mul(quickPow(sub(i * 2, D), n), ifac[D - i]);
195     g[i] = mul(F(i), quickPow(2, D - i), ifac[D - i]);
196   }
197   Poly::multiply(f, D + 1, g, D + 1, h);
198   int answer = 0;
199   For(i, D, D * 2) {
200     answer = add(answer, mul((i - D) % 2 ? MOD - 1 : 1, ifac[i - D], h[i]));
201   }
202   printf("%d\n", mul(answer, fac[D], quickPow(quickPow(2, D), MOD - 2)));
203   return 0;
204 }
View Code

 无处安放

提答,不写。

田野

不会。

重复

考虑先取$s$的最长满足任意子串都大于等于等长前缀,任意后缀都大于等长前缀的前缀,这个可以KMP实现。

然后将条件容斥成任意子串都大于等于$s$的串的数量,再取$s$的前驱(一定能取到),大于等于就变成了大于。

现在我们有一个性质:任意合法串和一些形如$s$的前缀加上一个大于$s$下一个字符的字符的串的拼接一一对应。

证明可以通过取最小表示实现,脑补也行。

那么就是一个线性递推了,这个数据范围下求逆更好一些。

  1 #include <bits/stdc++.h>
  2 
  3 #define IL __inline__ __attribute__((always_inline))
  4 
  5 #define For(i, a, b) for (int i = (a), i##end = (b); i <= i##end; ++ i)
  6 #define FOR(i, a, b) for (int i = (a), i##end = (b); i < i##end; ++ i)
  7 #define Rep(i, a, b) for (int i = (a), i##end = (b); i >= i##end; -- i)
  8 #define REP(i, a, b) for (int i = (a) - 1, i##end = (b); i >= i##end; -- i)
  9 
 10 typedef long long LL;
 11 
 12 template <class T>
 13 IL bool chkmax(T &a, const T &b) {
 14   return a < b ? ((a = b), 1) : 0;
 15 }
 16 
 17 template <class T>
 18 IL bool chkmin(T &a, const T &b) {
 19   return a > b ? ((a = b), 1) : 0;
 20 }
 21 
 22 template <class T>
 23 IL T mymax(const T &a, const T &b) {
 24   return a > b ? a : b;
 25 }
 26 
 27 template <class T>
 28 IL T mymin(const T &a, const T &b) {
 29   return a < b ? a : b;
 30 }
 31 
 32 template <class T>
 33 IL T myabs(const T &a) {
 34   return a > 0 ? a : -a;
 35 }
 36 
 37 const int INF = 0X3F3F3F3F;
 38 const double EPS = 1E-10, PI = acos(-1.0);
 39 
 40 #define DEBUG(...) fprintf(stderr, __VA_ARGS__)
 41 #define OK DEBUG("Passing [%s] in LINE %d...\n", __FUNCTION__, __LINE__)
 42 
 43 namespace Math {
 44 const int MOD = 998244353;
 45 
 46 IL int add(int a, int b) {
 47   a += b;
 48   return a >= MOD ? a - MOD : a;
 49 }
 50 
 51 template <class ...Args>
 52 IL int add(int a, const Args &...args) {
 53   a += add(args...);
 54   return a >= MOD ? a - MOD : a;
 55 }
 56 
 57 IL int sub(int a, int b) {
 58   a -= b;
 59   return a < 0 ? a + MOD : a;
 60 }
 61 
 62 IL int mul(int a, int b) {
 63   return (LL)a * b % MOD;
 64 }
 65 
 66 template <class ...Args>
 67 IL int mul(int a, const Args &...args) {
 68   return (LL)a * mul(args...) % MOD;
 69 }
 70 
 71 IL int quickPow(int a, int p) {
 72   int result = 1;
 73   for (; p; p >>= 1, a = mul(a, a)) {
 74     if (p & 1) {
 75       result = mul(result, a);
 76     }
 77   }
 78   return result;
 79 }
 80 }
 81 
 82 using namespace Math;
 83 
 84 const int MAXN = 100000 + 5, LOG = 18, G = 3, G_inv = 332748118, INV_2 = 499122177;
 85 
 86 int inv[1 << LOG];
 87 
 88 IL void init(int n) {
 89   inv[1] = 1;
 90   For(i, 2, n) {
 91     inv[i] = mul(inv[MOD % i], MOD - MOD / i);
 92   }
 93 }
 94 
 95 namespace Poly {
 96 int pos[1 << LOG], root[1 << LOG], root_inv[1 << LOG], len;
 97 
 98 IL void init(int n) {
 99   for (; 1 << len < n; ++ len);
100   FOR(i, 0, 1 << len) {
101     pos[i] = (pos[i >> 1] >> 1) | ((i & 1) << (len - 1));
102   }
103   int w = quickPow(G, (MOD - 1) >> len);
104   root[0] = 1;
105   FOR(i, 1, 1 << len) {
106     root[i] = mul(root[i - 1], w);
107   }
108   w = quickPow(G_inv, (MOD - 1) >> len);
109   root_inv[0] = 1;
110   FOR(i, 1, 1 << len) {
111     root_inv[i] = mul(root_inv[i - 1], w);
112   }
113 }
114 
115 IL void NTT(int *a, int n, int *root) {
116   int shift = __builtin_ctz((1 << len) / n);
117   FOR(i, 0, n) {
118     if (i > pos[i] >> shift) {
119       std::swap(a[i], a[pos[i] >> shift]);
120     }
121   }
122   for (int i = 2; i <= n; i <<= 1) {
123     int k = i >> 1;
124     shift = __builtin_ctz((1 << len) / i);
125     for (int *p = a; p != a + n; p += i) {
126       FOR(j, 0, k) {
127         int temp = mul(p[j + k], root[j << shift]);
128         p[j + k] = sub(p[j], temp);
129         p[j] = add(p[j], temp);
130       }
131     }
132   }
133 }
134 
135 IL void DFT(int *a, int n) {
136   NTT(a, n, root);
137 }
138 
139 IL void IDFT(int *a, int n) {
140   NTT(a, n, root_inv);
141   int inv_n = quickPow(n, MOD - 2);
142   FOR(i, 0, n) {
143     a[i] = mul(a[i], inv_n);
144   }
145 }
146 
147 IL void multiply(int *a, int n, int *b, int m, int *result) {
148   int len = 0;
149   for (; 1 << len < n + m; ++ len);
150   static int x[1 << LOG], y[1 << LOG];
151   std::copy(a, a + n, x);
152   memset(x + n, 0, ((1 << len) - n) * sizeof (int));
153   std::copy(b, b + m, y);
154   memset(y + m, 0, ((1 << len) - m) * sizeof (int));
155   memset(result, 0, (1 << len) * sizeof (int));
156   DFT(x, 1 << len);
157   DFT(y, 1 << len);
158   FOR(i, 0, 1 << len) {
159     result[i] = mul(x[i], y[i]);
160   }
161   IDFT(result, 1 << len);
162   memset(result + n + m - 1, 0, ((1 << len) - n - m + 1) * sizeof (int));
163 }
164 
165 void inverse(int *f, int *g, int t) {
166   if (t == 1) {
167     g[0] = quickPow(f[0], MOD - 2);
168     return;
169   }
170   inverse(f, g, (t + 1) >> 1);
171   int len = 0;
172   for (; 1 << len < t << 1; ++ len);
173   static int temp[1 << LOG];
174   std::copy(f, f + t, temp);
175   memset(temp + t, 0, ((1 << len) - t) * sizeof (int));
176   DFT(temp, 1 << len);
177   DFT(g, 1 << len);
178   FOR(i, 0, 1 << len) {
179     g[i] = mul(g[i], sub(2, mul(temp[i], g[i])));
180   }
181   IDFT(g, 1 << len);
182   memset(g + t, 0, ((1 << len) - t) * sizeof (int));
183 }
184 
185 IL void reverse(int *f, int n) {
186   std::reverse(f, f + n);
187 }
188 
189 IL void inc(int *f, int *g, int n, int *result) {
190   FOR(i, 0, n) {
191     result[i] = add(f[i], g[i]);
192   }
193 }
194 
195 IL void dec(int *f, int *g, int n, int *result) {
196   FOR(i, 0, n) {
197     result[i] = sub(f[i], g[i]);
198   }
199 }
200 
201 IL void divide(int *f, int n, int *g, int m, int *q, int *r) {
202   reverse(f, n), reverse(g, m);
203   int len = 0;
204   for (; 1 << len < n + m; ++ len);
205   static int temp[1 << LOG];
206   memset(temp, 0, (1 << len) * sizeof (int));
207   inverse(g, temp, n - m + 1);
208   multiply(f, n - m + 1, temp, n - m + 1, q);
209   reverse(q, n - m + 1);
210   reverse(f, n), reverse(g, m);
211   multiply(g, m, q, n - m + 1, temp);
212   dec(f, temp, n, r);
213 }
214 
215 IL void derive(int *f, int n, int *result) {
216   FOR(i, 0, n - 1) {
217     result[i] = mul(f[i + 1], i + 1);
218   }
219 }
220 
221 IL void integrate(int *f, int n, int *result) {
222   Rep(i, n, 1) {
223     result[i] = mul(f[i - 1], inv[i]);
224   }
225   result[0] = 0;
226 }
227 
228 IL void ln(int *f, int *g, int n) {
229   int len = 0;
230   for (; 1 << len < n; ++ len);
231   static int temp1[1 << LOG], temp2[1 << LOG];
232   memset(temp1, 0, (1 << len) * sizeof (int));
233   memset(temp2, 0, (1 << len) * sizeof (int));
234   inverse(f, temp1, n);
235   derive(f, n, temp2);
236   multiply(temp1, n, temp2, n - 1, g);
237   integrate(g, n - 1, g);
238 }
239 
240 void exp(int *f, int *g, int t) {
241   if (t == 1) {
242     g[0] = 1;
243     return;
244   }
245   exp(f, g, (t + 1) >> 1);
246   int len = 0;
247   for (; 1 << len < t << 1; ++ len);
248   static int temp1[1 << LOG], temp2[1 << LOG];
249   memset(temp1, 0, (1 << len) * sizeof (int));
250   ln(g, temp1, t);
251   std::copy(f, f + t, temp2);
252   memset(temp2 + t, 0, ((1 << len) - t) * sizeof (int));
253   ++ temp2[0];
254   dec(temp2, temp1, t, temp2);
255   multiply(temp2, t, g, t, g);
256   memset(g + t, 0, ((1 << len) - t) * sizeof (int));
257 }
258 
259 void sqrt(int *f, int *g, int t) {
260   if (t == 1) {
261     g[0] = 1;
262     return;
263   }
264   sqrt(f, g, (t + 1) >> 1);
265   int len = 0;
266   for (; 1 << len < t << 1; ++ len);
267   static int temp[1 << LOG];
268   memset(temp, 0, (1 << len) * sizeof (int));
269   inverse(g, temp, t);
270   multiply(f, t, temp, t, temp);
271   inc(g, temp, t, g);
272   FOR(i, 0, t) {
273     g[i] = mul(g[i], INV_2);
274   }
275 }
276 
277 int pre_work[LOG][MAXN * 8];
278 
279 void decompositionNTT(int *a, int level, int l, int r) {
280   if (l + 1 >= r) {
281     pre_work[level][l << 1] = sub(0, a[l]);
282     pre_work[level][l << 1 | 1] = 1;
283     return;
284   }
285   int mid = (l + r) >> 1;
286   decompositionNTT(a, level + 1, l, mid);
287   decompositionNTT(a, level + 1, mid, r);
288   static int temp[1 << LOG];
289   multiply(pre_work[level + 1] + (l << 1), mid - l + 1, pre_work[level + 1] + (mid << 1), r - mid + 1, temp);
290   std::copy(temp, temp + r - l + 1, pre_work[level] + (l << 1));
291 }
292 
293 int result_eval[LOG][1 << LOG];
294 
295 void getEvaluation(int *f, int *g, int level, int l, int r) {
296   static int temp[1 << LOG];
297   if (level) {
298     divide(f, ((r - l) << 1) + 1, pre_work[level] + (l << 1), r - l + 1, temp, result_eval[level] + l);
299   } else {
300     std::copy(f + l, f + r, result_eval[level] + l);
301   }
302   if (l + 1 >= r) {
303     g[l] = result_eval[level][l];
304     return;
305   }
306   int mid = (l + r) >> 1;
307   getEvaluation(result_eval[level] + l, g, level + 1, l, mid);
308   getEvaluation(result_eval[level] + l, g, level + 1, mid, r);
309 }
310 
311 IL void evaluate(int *a, int *f, int n, int *g) {
312   decompositionNTT(a, 0, 0, n);
313   getEvaluation(f, g, 0, 0, n);
314 }
315 
316 void decompositionNTT(int *f, int *g, int level, int l, int r) {
317   if (l + 1 >= r) {
318     f[l] = g[l];
319     return;
320   }
321   int mid = (l + r) >> 1;
322   decompositionNTT(f, g, level + 1, l, mid);
323   decompositionNTT(f, g, level + 1, mid, r);
324   static int temp1[1 << LOG], temp2[1 << LOG];
325   multiply(f + l, mid - l, pre_work[level + 1] + (mid << 1), r - mid + 1, temp1);
326   multiply(f + mid, r - mid, pre_work[level + 1] + (l << 1), mid - l + 1, temp2);
327   FOR(i, l, r) {
328     f[i] = add(temp1[i - l], temp2[i - l]);
329   }
330 }
331 
332 IL void interpolate(int *x, int *y, int n, int *f) {
333   decompositionNTT(x, 0, 0, n);
334   static int temp1[1 << LOG], temp2[1 << LOG];
335   std::copy(pre_work[0], pre_work[0] + n + 1, temp1);
336   derive(temp1, n + 1, temp1);
337   getEvaluation(temp1, temp2, 0, 0, n);
338   FOR(i, 0, n) {
339     temp2[i] = mul(y[i], quickPow(temp2[i], MOD - 2));
340   }
341   decompositionNTT(f, temp2, 0, 0, n);
342 }
343 }
344 
345 char str[MAXN];
346 int nxt[MAXN], f[MAXN], g[MAXN];
347 
348 int main() {
349   int m;
350   scanf("%d", &m);
351   init(m);
352   Poly::init(m << 1);
353   scanf("%s", str + 1);
354   int n = strlen(str + 1);
355   For(i, 2, n) {
356     int cur = i - 1;
357     while (nxt[cur] && str[nxt[cur] + 1] != str[i]) {
358       cur = nxt[cur];
359     }
360     nxt[i] = nxt[cur] + (str[nxt[cur] + 1] == str[i]);
361   }
362   for (int i = 1; i < n; ++ i) {
363     if (str[i + 1] < str[nxt[i] + 1]) {
364       n = i;
365     }
366   }
367   while (nxt[n]) {
368     -- n;
369   }
370   if (n > m) {
371     n = m;
372   } else {
373     -- str[n];
374   }
375   f[0] = 1;
376   For(i, 1, n) {
377     f[i] = sub(str[i], 'z');
378   }
379   Poly::inverse(f, g, m + 1);
380   int answer = sub(quickPow(26, m), g[m]);
381   For(i, 2, m) {
382     answer = add(answer, mul(i - 1, f[i], g[m - i]));
383   }
384   printf("%d\n", answer);
385   return 0;
386 }
View Code

 氪金手游

先考虑如果树是一棵外向树怎么做:令$f_{i,j}$为$i$节点子树权值和为$j$时的概率,转移类似于背包。

问题是现在有反向边,那我们可以把它容斥掉(无视这条边的答案减去这条边反向的答案),转移时乘上一个-1的容斥系数即可。

  1 #include <bits/stdc++.h>
  2 
  3 #define IL __inline__ __attribute__((always_inline))
  4 
  5 #define For(i, a, b) for (int i = (a), i##end = (b); i <= i##end; ++ i)
  6 #define FOR(i, a, b) for (int i = (a), i##end = (b); i < i##end; ++ i)
  7 #define Rep(i, a, b) for (int i = (a), i##end = (b); i >= i##end; -- i)
  8 #define REP(i, a, b) for (int i = (a) - 1, i##end = (b); i >= i##end; -- i)
  9 
 10 typedef long long LL;
 11 
 12 template <class T>
 13 IL bool chkmax(T &a, const T &b) {
 14   return a < b ? ((a = b), 1) : 0;
 15 }
 16 
 17 template <class T>
 18 IL bool chkmin(T &a, const T &b) {
 19   return a > b ? ((a = b), 1) : 0;
 20 }
 21 
 22 template <class T>
 23 IL T mymax(const T &a, const T &b) {
 24   return a > b ? a : b;
 25 }
 26 
 27 template <class T>
 28 IL T mymin(const T &a, const T &b) {
 29   return a < b ? a : b;
 30 }
 31 
 32 template <class T>
 33 IL T myabs(const T &a) {
 34   return a > 0 ? a : -a;
 35 }
 36 
 37 const int INF = 0X3F3F3F3F;
 38 const double EPS = 1E-8, PI = acos(-1.0);
 39 
 40 #define DEBUG(...) fprintf(stderr, __VA_ARGS__)
 41 #define OK DEBUG("Passing [%s] in LINE %d...\n", __FUNCTION__, __LINE__)
 42 
 43 namespace Math {
 44 const int MOD = 998244353;
 45 
 46 IL int add(int a, int b) {
 47   a += b;
 48   return a >= MOD ? a - MOD : a;
 49 }
 50 
 51 template <class ...Args>
 52 IL int add(int a, const Args &...args) {
 53   a += add(args...);
 54   return a >= MOD ? a - MOD : a;
 55 }
 56 
 57 IL int sub(int a, int b) {
 58   a -= b;
 59   return a < 0 ? a + MOD : a;
 60 }
 61 
 62 IL int mul(int a, int b) {
 63   return (LL)a * b % MOD;
 64 }
 65 
 66 template <class ...Args>
 67 IL int mul(int a, const Args &...args) {
 68   return (LL)a * mul(args...) % MOD;
 69 }
 70 
 71 IL int quickPow(int a, int p) {
 72   int result = 1;
 73   for (; p; p >>= 1, a = mul(a, a)) {
 74     if (p & 1) {
 75       result = mul(result, a);
 76     }
 77   }
 78   return result;
 79 }
 80 }
 81 
 82 using namespace Math;
 83 
 84 const int MAXN = 1000 + 5;
 85 
 86 int a[MAXN][4], inv[MAXN * 3];
 87 
 88 struct Tree {
 89   int hed[MAXN], nxt[MAXN * 2], to[MAXN * 2], fa[MAXN], size[MAXN], f[MAXN][MAXN * 3], g[MAXN][MAXN * 3], cnt;
 90   bool dir[MAXN * 2];
 91 
 92   void addEdge(int u, int v, bool d) {
 93     ++ cnt;
 94     dir[cnt] = d;
 95     to[cnt] = v;
 96     nxt[cnt] = hed[u];
 97     hed[u] = cnt;
 98   }
 99 
100   void DFS(int u) {
101     size[u] = 1;
102     For(i, 1, 3) {
103       f[u][i] = a[u][i];
104     }
105     for (int e = hed[u]; e; e = nxt[e]) {
106       int v = to[e];
107       if (v != fa[u]) {
108         fa[v] = u;
109         DFS(v);
110         For(i, 1, (size[u] + size[v]) * 3) {
111           g[u][i] = 0;
112         }
113         if (dir[e]) {
114           For(i, 1, size[u] * 3) {
115             For(j, 1, size[v] * 3) {
116               g[u][i + j] = add(g[u][i + j], mul(f[u][i], f[v][j], i, inv[i + j]));
117             }
118           }
119         } else {
120           For(i, 1, size[u] * 3) {
121             For(j, 1, size[v] * 3) {
122               g[u][i + j] = sub(g[u][i + j], mul(f[u][i], f[v][j], i, inv[i + j]));
123               g[u][i] = add(g[u][i], mul(f[u][i], f[v][j]));
124             }
125           }
126         }
127         size[u] += size[v];
128         std::copy(g[u] + 1, g[u] + size[u] * 3 + 1, f[u] + 1);
129       }
130     }
131   }
132 } T;
133 
134 int main() {
135   int n;
136   scanf("%d", &n);
137   inv[1] = 1;
138   For(i, 2, n * 3) {
139     inv[i] = mul(inv[MOD % i], MOD - MOD / i);
140   }
141   For(i, 1, n) {
142     scanf("%d%d%d", &a[i][1], &a[i][2], &a[i][3]);
143     int s = quickPow(a[i][1] + a[i][2] + a[i][3], MOD - 2);
144     a[i][1] = mul(a[i][1], s), a[i][2] = mul(a[i][2], s), a[i][3] = mul(a[i][3], s);
145   }
146   For(i, 2, n) {
147     int u, v;
148     scanf("%d%d", &u, &v);
149     T.addEdge(u, v, 1);
150     T.addEdge(v, u, 0);
151   }
152   T.DFS(1);
153   int answer = 0;
154   For(i, 1, n * 3) {
155     answer = add(answer, T.f[1][i]);
156   }
157   printf("%d\n", answer);
158   return 0;
159 }
View Code

 

posted @ 2019-05-30 16:59  sjkmost  阅读(469)  评论(0编辑  收藏  举报