Codeforces Round #428 (Div. 2) 题解(ABC)

来源:互联网 发布:mac银河雪山 编辑:程序博客网 时间:2024/06/05 19:14

写在前面

我的第二篇博客:补一下第五场Codeforces.
AC了两道,B题FST,D题没思路,E没看。
rank1489,分数1517-1523 加了6分。

839A : Arya and Bran (简单模拟)

给定n(100),k(1000),n个数ai(100)代表n天获得的糖。每天k-=min(现存糖数,8),求第几天结束后k<=0,如果不能达到,输出-1。

#include <cstdio>#include <algorithm>using namespace std;int a[110];int main(void){    int n,k,now=0,cnt;    scanf("%d%d",&n,&k);    for(int i=0;i<n;i++)    {        scanf("%d",&a[i]);    }    for(cnt=0;cnt<n;cnt++)    {        now+=a[cnt];        int p=min(now,8);        k-=p;        if(k<=0)            break;        now-=p;    }    if(k>0)        printf("-1\n");    else        printf("%d\n",cnt+1 );    return 0;}

代码用时:10分钟,因为重写时看错了题。
AC用时:10分钟。感觉需要一个好用的初始模板。

839B : Game of the Rows (贪心, 模拟)

给定n(10000),k(100),k个整数ai(10000)。
有n排座位,每排都是2空4空2,k组士兵,能否安排这些士兵不同组之间横向不相邻地坐下?
比较繁琐的模拟,容易写错,很考验基本功和思维。

把所有组分成对4取模分成4个,2个,1个(3个等价于1个+2个)。
大座位个数为n,小座位个数为n*2
现在有4,2,1,大(座位),小
让4坐大
+++如果坐完大,剩下4,2,1,小,比较2*n4+n2+n1n小
+++如果坐完4,剩下2,1,大,小
+++让2坐小
++++++如果坐完2,剩下1,大,小,比较n1n大*2+n小
++++++如果坐完小,剩下2,1,大
++++++让1坐大(只坐一次,相当于把大转化为小)
+++++++++如果坐完1,剩下2,大,小,比较n2n大*3/2+n小
+++++++++如果坐完大,剩下2,1,小,比较n2+n1n小

#include <cstdio>int s4,s2,p1,p2,p4;int solve(){    if(p4 < s4)    {        s4 -= p4;        if(p2 < s2)        {            s2 -= p2;            return p1 <= 2 * s4 + s2;        }        else        {            p2 -= s2;            s2 = 0;            if(p1 < s4)            {                s2 += p1;                s4 -= p1;                return p2 <= s4 * 3 / 2 + s2;            }            else            {                s2 += s4;                p1 -= s4;                return p2 + p1 <= s2;            }        }    }    else    {        p4 -= s4;        return p4*2 + p2 + p1 <= s2;    }}int main(void){    int n, k;    scanf("%d%d", &n, &k);    s4=n;s2=n*2;    while(k--)    {        int tmp;        scanf("%d", &tmp);        p4 += tmp / 4;        switch(tmp % 4)        {            case 0:break;            case 1:p1++;break;            case 2:p2++;break;            case 3:p2++;p1++;break;        }    }    printf("%s\n", solve() ? "Yes" : "No" );    return 0;}

重写时间:40分钟。(果然熬夜效率低)
总结:写大模拟题一定要静下心来,一急躁就会犯错,出现莫名其妙的bug。
事先一定要写好算法,代码结构一定要清晰,方便debug。

839C : Journey (简单的树上dfs)

给定n(1e5)和n-1个数对代表一棵n个点的树,从根节点(1号点)出发,等概率地由父节点向子节点行进,到达叶子时停止,求路径长度的期望(每条边的长度为1)。

构建一棵树,每个节点结构体包括:当前概率,子节点集,当前深度。dfs即可,注意下个节点的概率=当前概率/当前子节点集容量。每到一个叶子节点,ans+=当前深度*当前概率。

#include <cstdio>#include <stack>#include <set>using namespace std;struct Item{    double poss;    set<int> edge;    int deep;} item[100010];double dfs(){    double ans = 0.0;    stack<int> s;    s.push(1);    item[1].poss = 1.0;    while(!s.empty())    {        int x = s.top();        s.pop();        for(auto nex : item[x].edge)        {            item[nex].poss = item[x].poss / item[x].edge.size();            item[nex].deep = item[x].deep + 1;            item[nex].edge.erase(x);            s.push(nex);        }        if(item[x].edge.size() == 0)            ans += item[x].deep * item[x].poss;    }    return ans;}int main(void){    int n;    scanf("%d", &n);    for(int i = 0; i < n - 1; i++)    {        int ti, tj;        scanf("%d%d", &ti, &tj);        item[ti].edge.insert(tj);        item[tj].edge.insert(ti);    }    printf("%.9f\n", dfs() );    return 0;}

AC用时:1小时26分钟。(我也不知道为什么花了这么长时间……)
重写用时:13分钟。

839D : Winter is here (数论)

给定n(2e5)和n个整数ai(1e6)。若干最大公因数大于1的数可以看成一个clan,一个clan的贡献为gcd乘clan大小。求所有clan(一个数可以属于多个clan)的贡献和,结果模1e9+7。

先留坑,需要用到容斥原理/莫比乌斯反演,学会之后来做。