2018.9.29 ???模拟赛

*注意:这套题目应版权方要求,不得公示题面。

从这里开始

  T1又是我不擅长的构造题,好不容猜出结论,然后没开long long,发现还是10分以为是错的,sad。T3傻逼推错式子,30分dp都挂掉了。下午补了补多项式求exp,然后Joker给我科普了一个式子,然后就会做了,发现多项式求$\ln$的板子丢了,重新写,挂了边界问题调了大半个下午,sad。真是sad的一天。

Problem A Caster的矩阵

题目大意

  构造一个$n\times n$的矩阵,使得$1, 2, 3, \dots, n^{2}$各出现1次,要求最小化每行和每列的最大值与最小值之差的最大值。

  当$n\leqslant 600$时要求输出方案,否则只输出最小的值。$m$为偶数。

  手玩$n = 2, 4, 6$的时候发现答案分别为$2, 9, 20$,猜想答案是关于边长的二次函数,然后得到:$ans = \frac{1}{2}n^{2} + \frac{1}{2}n - 1$。

  我们来想一下,这个式子有着什么意义(瞎猜):$\frac{1}{2}n^{2}$是半个矩阵的大小,$\frac{1}{2}n$是半行,$-1$是和$1$作差。

  它启示我们要把矩阵分成两部分。

  然后怎么填呢?把前一半的数在左半边从小到大依次从左往右,从上到下填入矩阵,对于右半部分类似。

  这样可以发现每一行的最大值和最小值值之差是$\frac{1}{2}n^{2} + \frac{1}{2}n - 1$,每一列的最大值与最小值之差是$\frac{1}{2}n^{2} - \frac{n}{2}$。

  我们怎么来证明呢?

  考虑设$S = \frac{1}{2}n^{2} + \frac{1}{2}n - 1$把所有数分成两类$1 ~ x$和$(x + S) ~ n^{2}$,其他数暂时不管。

  为了证明答案,取$x = \frac{1}{4}n^{2} - \frac{1}{2}n + 1$。

  • 当两个属于不同集合存在于同一行或同一列的时候,答案大于等于$S$。
  • 假设第一类的数占据了$a$行和$b$列, 显然$ab \geqslant x$,然后有$a + b\geqslant \sqrt{ab} \geqslant 2\sqrt{x} = \sqrt{n^2 - 2n + 2} > n - 1$,即$a + b \geqslant n$。
  • 假设第二类的数占据了$c$行和$d$列,显然$cd \geqslant n^{2} - x - S + 1 = \frac{1}{4}n^{2} + 1$,然后有$c + d\geqslant \sqrt{cd} \geqslant 2 \sqrt{ \frac{1}{4}n^2 + 1} = \sqrt{n^{2} + 4} > n$
  • 所以$a + b + c + d > 2n$,由抽屉原理可知必然存在一个元素存在于同一行或同一列。

Code

 1 #include <iostream>
 2 #include <cstdlib>
 3 #include <cstdio>
 4 using namespace std;
 5 typedef bool boolean;
 6 
 7 int n;
 8 inline void init() {
 9     scanf("%d", &n);
10 }
11 
12 inline void solve() {
13     if (n <= 600) {
14         int m = n >> 1;
15         for (int i = 1; i <= n; i++) {
16             int s = (i - 1) * m;
17             for (int j = 1; j <= m; j++)
18                 printf("%d ", s + j);
19             s += (m * m) * 2;
20             for (int j = 1; j <= m; j++)
21                 printf("%d ", s + j);
22             putchar(10);    
23         }
24     }
25     cout << ((n * 1ll * n) / 2 + n / 2 - 1) << endl;
26 }
27 
28 int T;
29 int main() {
30     scanf("%d", &T);
31     while (T--) {
32         init();
33         solve();
34     }
35     return 0;
36 }
Problem A

Problem B Berserker的power

题目大意

  有$n$个随机变量$x_{1}, x_{2}, \cdots, x_{n}$,第$i$个随机变量等概率取到$[l_{i}, r_{i}]$间的任意一个实数。问$\max((\sum_{i = 1}^{n}x_{i})^{m}, a^{m})$的期望。

  取个$\max$纯属增加代码量。

  设$f_{i}(x)$表示只考虑前$i$个随机变量的和为$x$的概率。每加入一个数,相当于对前面的某一段闭区间做了一次积分,然后可以拆成"前缀和"相减的形式,递归下去,变成在$f_{1}(x)$若干段区间做$n$阶积分。然后分$m$奇偶性讨论。

  好了嘴巴AC了。改天再写代码。

Problem C Assassin的森林

题目大意

  问$n$个点的带标号基环树森林的个数。

  (纪中的多项式板子的运行效率咋集体被我们爆踩?)

  感觉不是很难,但比较套路。

  显然,考虑维护一下这么几个东西:

  $f_{n,k}$表示$n$个点且基环大小为$k$的基环树个数。

  $g_{n}$表示$n$个点的基环树个数。

  $h_{n}$表示$n$个点的基环树森林个数。

  转移都很简单啦。

  $f_{n, k} = \frac{1}{2k}\sum_{i = 1}^{n}f_{n - i, k - 1}C_{n - 1}^{i - 1}i^{i - 1}$。

  解释就是枚举当前向环上加入的有根树的大小,然后考虑拿出哪些点,为了防止算重,强行要求包含标号最大的点。由于这个形成一条有向链套树,变成环套树需要除以$2k$。

  $g_{n} = \sum_{k = 3}^{n}f_{n,k} + n^{n - 2}$。

  $h_{n} = \sum_{k = 1}^{n}g_{k}h_{n - k}C_{n - 1}^{k - 1}$。

  于是我们得到了30分的高分。

  然后考虑用生成函数来优化这个做法。

  第一部分考虑我们其实是将一堆带标号有根树拼成有根链,然后变成环。

  设有根树的指数生成函数是$F^{(e)}(x) = \sum_{i = 1}^{\infty} \frac{1}{i!}i^{i - 1}x^{i}$。

  我们考虑这样一个指数生成函数

$G^{(e)}(x) = \sum_{n = 0}^{\infty} \frac{(n - 1)!F^{(e)}(x)^{n}}{2(n!)}=\frac{1}{2}\sum_{n=0}^{\infty}\frac{F^{(e)}(x)^{n}}{n} = -\frac{1}{2}\ln(1 - F^{(e)}(x))$

  发现减去$n = 1, n = 2$的两项后,每一项再补上$n^{n - 2}$后就是我们想要的$g_{n}$的指数生成函数。

  剩下就很简单,直接求exp就得到$h_{n}$的指数生成函数。

Code

  1 #include <bits/stdc++.h>
  2 using namespace std;
  3 typedef bool boolean;
  4 
  5 const int N = 262144;
  6 const int bzmax = 20;
  7 const int M = 998244353;
  8 const int g = 3;
  9 const int inv2 = (M + 1) >> 1;
 10 
 11 int qpow(int a, int p) {
 12     if (p < 0)
 13         p += M - 1;
 14     int rt = 1, pa = a;
 15     for ( ; p; p >>= 1, pa = pa * 1ll * pa % M)
 16         if (p & 1)
 17             rt = rt * 1ll * pa % M;
 18     return rt;
 19 }
 20 
 21 int add(int a, int b) {
 22     return ((a += b) >= M) ? (a - M) : (a);
 23 }
 24 
 25 int sub(int a, int b) {
 26     return ((a -= b) < 0) ? (a + M) : (a);
 27 }
 28 
 29 class NTT {
 30     public:
 31         int gn[bzmax], _gn[bzmax];
 32         
 33         NTT() {
 34             for (int i = 0, L = 2; i < bzmax; i++, L <<= 1) {
 35                 gn[i] = qpow(g, (M - 1) / L);
 36                 _gn[i] = qpow(g, -(M - 1) / L);
 37             }
 38         }
 39 
 40         void operator () (int* f, int len, int sgn) {
 41             for (int i = 1, j = len >> 1, k; i < len - 1; i++, j += k) {
 42                 if (i < j)
 43                     swap(f[i], f[j]);
 44                 for (k = len >> 1; j >= k; j -= k, k >>= 1);
 45             }
 46 
 47             for (int b = 2, t = 0; b <= len; b <<= 1, t++) {
 48                 int wn = ((sgn > 0) ? (gn[t]) : (_gn[t])), w = 1, hb = b >> 1;
 49                 for (int i = 0; i < len; i += b, w = 1)
 50                     for (int j = i; j < i + hb; j++, w = w * 1ll * wn % M) {
 51                         int a = f[j], b = f[j + hb] * 1ll * w % M;
 52                         f[j] = add(a, b);
 53                         f[j + hb] = sub(a, b);
 54                     }
 55             }
 56 
 57             if (sgn < 0) {
 58                 int invlen = qpow(len, -1);
 59                 for (int i = 0; i < len; i++)
 60                     f[i] = f[i] * 1ll * invlen % M;
 61             }
 62         }
 63 
 64         int correctLen(int n) {
 65             int m = 1;
 66             while (m < n)    m <<= 1;
 67             return m;
 68         }
 69 }NTT;
 70 
 71 template<typename T>
 72 void pcopy(T* ns, T* ne, const T* os) {
 73     for ( ; ns != ne; *ns = *os, ns++, os++);
 74 }
 75 
 76 template<typename T>
 77 void pfill(T* ps, T* pt, T val) {
 78     for ( ; ps != pt; *ps = val, ps++);
 79 }
 80 
 81 void debug(const int* f, int n) {
 82     for (int i = 0; i < n; i++)
 83         cerr << f[i] << " ";
 84     cerr << endl;
 85 }
 86 
 87 void debugE(const int *f, int n) {
 88     int prod = 1;
 89     for (int i = 0; i < n; i++)
 90         cerr << f[i] * 1ll * prod % M << " ", prod = prod * 1ll * (i + 1) % M;
 91     cerr << endl;
 92 }
 93 
 94 void pol_inverse(const int *f, int *g, int n) {
 95     static int h[N];
 96     if (n == 1)
 97         g[0] = qpow(f[0], -1);
 98     else {
 99         pol_inverse(f, g, (n + 1) >> 1);
100 
101         int t = NTT.correctLen(n << 1 | 1);
102         pcopy(h, h + n, f);
103         pfill(h + n, h + t, 0);
104         NTT(h, t, 1);
105         NTT(g, t, 1);
106         for (int i = 0; i < t; i++)
107             g[i] = g[i] * 1ll * sub(2, g[i] * 1ll * h[i] % M) % M;
108         NTT(g, t, -1);
109         pfill(g + n, g + t, 0);
110     }
111 }
112 
113 void diff(int *f, int n) {
114     for (int i = 1; i < n; i++)
115         f[i - 1] = f[i] * 1ll * i % M;
116     f[n - 1] = 0;
117 }
118 
119 void integ(int *f, int n) {
120     for (int i = n; i; i--)
121         f[i] = f[i - 1] * 1ll * qpow(i, -1) % M;
122     f[0] = 0;
123 }
124 
125 void pol_ln(const int* f, int* g, int n) {
126     static int A[N], B[N];
127     int t = NTT.correctLen(n << 1 | 1);
128     pfill(g, g + t, 0);
129     pcopy(A, A + n, f);
130     pfill(A + n, A + t, 0);
131     diff(A, n);
132     pfill(B, B + t, 0);
133     pol_inverse(f, B, n);
134     NTT(A, t, 1);
135     NTT(B, t, 1);
136     for (int i = 0; i < t; i++)
137         g[i] = A[i] * 1ll * B[i] % M;
138     NTT(g, t, -1);
139     pfill(g + n - 1, g + t, 0);
140     integ(g, n);
141 }
142 
143 void pol_exp(int* f, int* g, int n) {
144     static int A[N];
145     if (n == 1)
146         g[0] = 1;
147     else {
148         int t = NTT.correctLen(n << 1 | 1);
149         pol_exp(f, g, (n + 1) >> 1);
150         
151         pol_ln(g, A, n);
152         for (int i = 0; i < n; i++)
153             A[i] = sub(f[i], A[i]);
154         A[0] = add(A[0], 1);
155         NTT(g, t, 1);
156         NTT(A, t, 1);
157         for (int i = 0; i < t; i++)
158             g[i] = g[i] * 1ll * A[i] % M;
159         NTT(g, t, -1);
160         pfill(g + n, g + t, 0);
161     }
162 }
163 
164 int n;
165 int Fe[N], rFe[N], Ge[N];
166 int fac[N];
167 
168 inline void init() {
169     scanf("%d", &n);
170     fac[0] = 1;
171     for (int i = 1; i <= n; i++)
172         fac[i] = fac[i - 1] * 1ll * i % M;
173     for (int i = 1; i <= n; i++)
174         Fe[i] = qpow(fac[i], -1) * 1ll * qpow(i, i - 1) % M;
175     for (int i = 1; i <= n; i++)
176         rFe[i] = M - Fe[i];
177     rFe[0] = 1;
178 }
179 
180 inline void solve() {
181     pol_ln(rFe, Ge, n + 1);
182     for (int i = 1; i <= n; i++)
183         Ge[i] = sub(sub(0, Ge[i]), Fe[i]);
184     int t = NTT.correctLen((n + 1) << 1);
185     NTT(Fe, t, 1);
186     for (int i = 0; i < t; i++)
187         Fe[i] = Fe[i] * 1ll * Fe[i] % M;
188     NTT(Fe, t, -1);
189     for (int i = 0; i <= n; i++)
190         Ge[i] = sub(Ge[i], Fe[i] * 1ll * inv2 % M) * 1ll * inv2 % M;
191     for (int i = 0; i <= n; i++)
192         Ge[i] = add(Ge[i], qpow(i, i - 2) * 1ll * qpow(fac[i], -1) % M);
193     pfill(Fe, Fe + t, 0);
194     pol_exp(Ge, Fe, n + 1);
195     printf("%d\n", Fe[n] * 1ll * fac[n] % M);
196 }
197 
198 int main() {
199     init();
200     solve();
201     return 0;
202 }
Problem C

猜你喜欢

转载自www.cnblogs.com/yyf0309/p/9726729.html