Codeforces Round #428 (Div. 2)

来源:互联网 发布:淘宝店铺怎么制作店招 编辑:程序博客网 时间:2024/05/18 01:17

Codeforces Round #428 (Div. 2)


第一次进20…纪念一下:

ranklist


B. Game of the Rows

全场fst题强行区分….这道题让我从60+变成了17…

其实只要记录现在有几个4人座,几个2人座,几个1人座(四人座变来的),然后分配的尽量减少空座位就行了…虽然总感觉有些不对..

#include <bits/stdc++.h>using namespace std;const int MAXN = 105;int n, k;int a[MAXN];int main(){    scanf("%d%d", &n, &k);    for (int i = 1; i <= k; i++) scanf("%d", &a[i]);    int F = n, T = 2*n, O = 0;    for (int i = 1; i <= k; i++) {        int num = a[i]/4;        if (F >= num) F -= num, a[i] -= 4*num;        else a[i] -= F*4, F = 0;        num = a[i]/2;        if (T >= num) T -= num, a[i] -= 2*num;        else a[i] -= 2*T, T = 0;        if (a[i] == 0) continue;        else if (a[i] == 1) {            if (O) O--;            else if (F) F--, T++;            else if (T) T--;            else { puts("NO"); return 0; }        } else if (a[i] == 2) {            if (F) F--, O++;            else if (O >= 2) O -= 2;            else { puts("NO"); return 0; }        } else if (a[i] == 3) {            if (O >= 3) O -= 3;            else if (F) F--;            else { puts("NO"); return 0; }        } else if (a[i] <= O) O -= a[i];        else { puts("NO"); return 0; }    }    puts("YES");    return 0;}

C. Journey

显然只有在叶子才会停…大力

#include <bits/stdc++.h>using namespace std;const int MAXN = 100005;struct node {    int to, next;} edge[MAXN*2];int head[MAXN], top = 0;inline void push(int i, int j){ edge[++top] = (node) {j, head[i]}, head[i] = top; }double len = 0;void dfs(int nd, int f, double p, int l){    int cnt = 0;    for (int i = head[nd]; i; i = edge[i].next) {        if (edge[i].to == f) continue;        cnt++;    }    for (int i = head[nd]; i; i = edge[i].next) {        if (edge[i].to == f) continue;        dfs(edge[i].to, nd, p/cnt, l+1);    }    if (cnt == 0) len += l*p; }int n, u, v;int main(){    scanf("%d", &n);    for (int i = 1; i < n; i++) {        scanf("%d%d", &u, &v);        push(u, v), push(v, u);    }    dfs(1, 0, 1, 0);    printf("%.15f\n", len);    return 0;}

D. Winter is here

题意:给定一个集合,求其所有子集的权值的和。集合的权值定义为:如果集合元素gcd为1,权值为0;否则权值为集合大小乘以gcd.

f(x)x|gcd的集合的大小总和。显而易见,这样的集合必然是所有x的倍数的子集。设这样的元素有n个,则集合总大小为:

kk(nk)=kn(n1k1)=nk(n1k)=n×2n1

g(x)x=gcd的集合的大小总和,则:

g(x)=f(x)i2g(ix)

最后的答案就是:

x2xg(x)

复杂度是O(nlnn).

#include <bits/stdc++.h>using namespace std;const int MAXN = 200005, mod = 1e9+7;int a[MAXN];int n;int f[MAXN*5], g[MAXN*5];int C[MAXN*5];inline int power(int a, int n){    int ans = 1;    for (int i = 0; i <= 30; i++) {        if (n&(1<<i)) ans = (long long)ans*a%mod;        a = (long long)a*a%mod;    }    return ans;}int main(){    scanf("%d", &n);    for (int i = 1; i <= n; i++) scanf("%d", &a[i]), C[a[i]]++;    for (register int i = 1; i <= 1000000; i++) {        int cnt = 0;        for (register int j = i; j <= 1000000; j += i)            cnt += C[j];        f[i] = (long long)cnt*power(2, cnt-1)%mod;    }    for (register int i = 1000000; i >= 1; i--) {        g[i] = f[i];        for (register int j = i*2; j <= 1000000; j += i)            g[i] = (g[i]-g[j])%mod;        (g[i] += mod) %= mod;    }    int tot = 0;    for (register int i = 2; i <= 1000000; i++)        tot = (tot+(long long)g[i]*i%mod)%mod;    (tot += mod) %= mod;    printf("%d\n", tot);    return 0;}

E. Mother of Dragons(补)

上午刚和小教室众王讨论过拉格朗日乘子法的奥义…然而不知道怎么限制xi0

std告诉我们,最优方法一定是给一个团均分,其他的都是0…至于证明…看不懂QwQ

考虑如何求最大团。可以用meet-in-the-middle来做…设第一块大小为S,第二块为nS,由于第一块要枚举子集方便第二块匹配,复杂度是:

O(3S+2nS)

求导并另导数为0,解得极值点S0.387n,带入做就好了。

#include <bits/stdc++.h>using namespace std;const int MAXN = 45;int g[MAXN][MAXN], f[MAXN], h[MAXN];int n, k;int st[1<<21|1];int main(){    scanf("%d%d", &n, &k);    for (int i = 0; i < n; i++) {        for (int j = 0; j < n; j++) {            scanf("%d", &g[i][j]);        }        g[i][i] = 1;    }    int L = max(1, int(n*0.387)), ans = 0;    memset(f, 0, sizeof f);    for (int i = 0; i < L; i++)        for (int j = 0; j < L; j++)            f[i] |= g[i][j]<<j;    for (int i = 0; i < 1<<L; i++) {        int sum = i, cnt = 0;        for (int j = 0; j < L; j++)            if (i&(1<<j))                sum &= f[j], cnt++;        if (sum == i) st[i] = cnt, ans = max(ans, cnt);    }    for (int i = 0; i < 1<<L; i++) {        int sub = i;        while (sub) {            st[i] = max(st[i], st[sub]);            sub = (sub-1)&i;        }    }    memset(f, 0, sizeof f);    for (int i = 0; i < n-L; i++) {        for (int j = 0; j < n-L; j++)             f[i] |= g[i+L][j+L]<<j;        for (int j = 0; j < L; j++)            h[i] |= g[i+L][j]<<j;    }    for (int i = 0; i < 1<<(n-L); i++) {        int sum = i, cc = (1<<L)-1, cnt = 0;        for (int j = 0; j < n-L; j++)            if (i&(1<<j))                sum &= f[j], cc &= h[j], cnt++;        if (sum == i) {                ans = max(ans, cnt+st[cc]);         }    }    if (ans == 0) puts("0.00000");    else         printf("%.10f\n", (double)k*k*(ans-1)/2/ans);    return 0;}
原创粉丝点击