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简单

首先要知道一点,对于一个每个点度数是确定的,它的生成树数量是

\[(n-2)!\prod \frac{1}{(in[i]-1)!} \]

通过\(prufer\)序列可以轻松得知

对于这题,因为它有有个\(d_i\)

所以我们这条式子应变成

\[(n-2)!\prod \frac{d_i^{\underline{in[i]}}}{(in[i]-1)!} \]

我们考虑生成函数
\(\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;
}
posted @ 2021-12-23 21:10  lahlah  阅读(37)  评论(0编辑  收藏  举报