AtCoder Regular Contest 106
菜的真实
C没看清楚数据范围炸了两发血亏
D用二项式定理展开一下就是个很naive的东西了
后两题比较有意思
E - Medals
首先可以发现天数的上限是\(2*n*1e5\)
显然可以二分答案
先考虑如何建图
左边是员工,右边是天数,根据\(Hall\)定理我们知道,对于左边的每个子集
\(G\),都要满足右边的连的点集\(|T|\ge |G|\)
放到这题,拓展一下,把每个员工拆成\(k\)个,就相当于是\(k|G|\le |T|\)
然后把每一天来的员工求出来,做个高维后缀和即可
code:
#include<bits/stdc++.h>
using namespace std;
const int N = (1 << 18) + 5;
int f[N], s[20000050], a[21], n, k, cnt[N];
int check(int mid) {
int lim = (1 << n);
for(int S = 0; S < lim; S ++) f[S] = 0;
for(int i = 1; i <= mid; i ++) f[lim - 1] ++, f[(lim - 1) ^ s[i]] --;
//for(int S = 0; S < lim; S ++) printf("%d ", f[S]); printf(" %d\n", mid);
for(int i = 0; i < n; i ++)
for(int S = 0; S < lim; S ++)
if(S & (1 << i)) f[S ^ (1 << i)] += f[S];
//for(int S = 0; S < lim; S ++) printf("%d ", f[S]); printf("\n");
for(int S = 0; S < lim; S ++) {
if(f[S] < cnt[S] * k) return 0;
}
return 1;
}
int main() {
scanf("%d%d", &n, &k);
for(int i = 1; i <= n; i ++) scanf("%d", &a[i]);
int lim = 2 * n * 100000 + 1;
for(int i = 1; i <= lim; i ++)
for(int j = 1; j <= n; j ++) {
if((i - 1) % (2 * a[j]) + 1 <= a[j]) {
s[i] |= (1 << (j - 1));
}
}
for(int i = 1; i < (1 << n); i ++) cnt[i] = cnt[i >> 1] + (i & 1);
int l = 0, r = lim;
// check(10);
while(l + 1 < r) {
int mid = (l + r) >> 1;
if(check(mid)) r = mid;
else l = mid;
}
printf("%d", r);
return 0;
}
F - Figures
好题,个人感觉并不比E简单
首先要知道一点,对于一个每个点度数是确定的,它的生成树数量是
通过\(prufer\)序列可以轻松得知
对于这题,因为它有有个\(d_i\)
所以我们这条式子应变成
我们考虑生成函数
设\(\large f_i(x)=\sum\limits_{j=0}^{d_i-1} \frac{d_i^{\underline{j+1}}}{j!}x^j\)
\(\large =\sum\limits_{j=0}^{d_i-1} \frac{d_i!}{j!(d_i-j-1)!}x^j\)
\(\large =d_i\sum\limits_{j=0}^{d_i-1} \frac{(d_i-1)!}{j!(d_i-j-1)!}x^j\)
\(\large =d_i\sum\limits_{j=0}^{d_i-1} \binom{d_i-1}{j}x^j\)
\(\large = d_i(x+1)^{d_i-1}\)
于是上面那条式子可以表示为
\(\large (n-2)! [x^{n-2}]\prod_{i=1} f_i(x)\)
\(=\large (n-2)! [x^{n-2}] \prod_{i=1}d_i(x+1)^{d_i-1}\)
\(=\large (n-2)! \prod_{i=1}d_i \ \ [x^{n-2}] (x+1)^{\sum d_i-1}\)
直接计算即可
code:
#include<bits/stdc++.h>
#define mod 998244353
using namespace std;
int n, sum, x;
int main() {
scanf("%d", &n);
int ans = 1;
for(int i = 1; i <= n; i ++) {
scanf("%d", &x); sum += x - 1; sum %= mod;
ans = 1ll * ans * x % mod;
}
for(int i = 0; i < n - 2; i ++) ans = 1ll * ans * (sum - i) % mod;
printf("%d", ans);
return 0;
}