Codeforces Round #429 (Div. 2) 题解(ABCD)

来源:互联网 发布:windows升级助手 编辑:程序博客网 时间:2024/05/17 08:31

写在前面:

我的第一篇博客 , 第六场Codeforces 。
比赛一共AC了3题,DE毫无思路。手速和知识,都需要练习。
排名1322,分数1523->1530,加了7分。

841A : Generous Kefa ( 简单模拟 )

简单的模拟,大意是给定n(1-100)、k(1-100)、n个小写字母组成的串,若某个小写字母的个数超过k输出Yes,均未超过输出No

#include <cstdio>int a[200];char s[200];int main(void){    int n,k,flag=1;    scanf("%d%d",&n,&k);    scanf("%s",s);    for(int i=0;i<n;i++)        a[s[i]]++;    for(int i='a';i<='z';i++)    {        if(a[i]>k)        {            flag=0;            break;        }    }    printf("%s",flag?"Yes":"No");    return 0;}

20行的代码,花了4分钟左右写完。
AC总用时:7分钟。读题和写代码花了较多时间。

841B : Godsend ( 简单博弈,找规律 )

一个(不公平的)博弈游戏,Excel找到规律:给n(1e6)和n个数字(1e9),有奇数输出First,否则输出Second。

#include <cstdio>int main(void){    int n,flag=0;    scanf("%d",&n);    while(n--)    {        int tmp;        scanf("%d",&tmp);        if(tmp&1)            flag=1;    }    printf("%s",flag?"First":"Second");    return 0;}

15行代码,1分钟左右写完。
AC总用时:16分钟。读题,思考和验证花了较多时间。

841C : Leha and Function ( 找规律,简单数学 )

读入m(2e5)和两个长度为m的序列A,B,找到A的一个排列A’使得F(A’i,Bi)求和最大。
打表找规律发现F(n,k)=(n+1)/(k+1),所以先将A排序,再按B的倒序映射输出即可。

#include <cstdio>#include <vector>#include <algorithm>#define M 200010using namespace std;int a[M],c[M];pair<int,int> b[M];int main(void){    int m;    scanf("%d",&m);    for(int i=0;i<m;i++)        scanf("%d",&a[i]);    for(int i=0;i<m;i++)    {        scanf("%d",&b[i].first);        b[i].second=i;    }    sort(a,a+m);    sort(b,b+m);    for(int i=0;i<m;i++)        c[b[i].second]=m-i-1;    for(int i=0;i<m;i++)        printf("%d ",a[c[i]]);    printf("\n");    return 0;}

28行代码,重写时6分钟写完。附一个问题:程序不要叫做cmd.cpp,否则会有意外的错误。
AC总用时:43分钟。找规律,猜想结论(如何使得商的和最大)花了较长时间。

841D : Leha and another game about graph( 补 ) (图论,dfs )

参考了@chudongfang2015 的题解。

读入n(3e5),m(n-1<=m<=3e5),n个点的权值(-1,0,1),m条无向边的两端。
求边的一个好子集,如果一个由所有的点和子集之中的边组成的图,-1点不限,0点的度数模2为0,1点的度数模2为1,这些边就构成了一个好子集。
输出任意一个好子集中的边数,以及边序号;如果不存在,输出-1。

如果存在-1点,那么-1点相邻的点也可以看成-1点,必存在解。
不存在-1点时,因为总度数(边数*2)必为偶数,所以,点权和为奇数不存在解,为偶数存在解(没有证明)。
按以上的判断方法,当存在解时,从-1点(不存在时,从任意点)开始dfs一次即可得出一个解。

#include <cstdio>#include <vector>#include <algorithm>#define M 300010using namespace std;int v_pri[M]; //点权vector <pair<int, int> > edge[M]; //边vector <int> ans; //结果int vis[M]; //是否已看过此点int have[M]; //是否已选中此边//dfs(当前点,上个点,边序号)void dfs(int x, int pre = 0, int e_idx = 0){    vis[x] = 1;    int pos = 0; //已经连了的边个数&1    for(auto i : edge[x])    {        if(vis[i.first])    continue;        dfs(i.first, x, i.second);        if(have[i.second])  pos ^= 1;    }    if(v_pri[x] != -1 && pos != v_pri[x])    {        have[e_idx] = 1;        if(e_idx != 0)  ans.push_back(e_idx);    }}int main(void){    int n, m;    int sum = 0, di = -1;    scanf("%d%d", &n, &m);    for(int i = 1; i <= n; i++)    {        scanf("%d", &v_pri[i]);        sum += v_pri[i];        if(v_pri[i] == -1)            di = i;    }    for(int i = 1; i <= m; i++)    {        int ti, tj;        scanf("%d%d", &ti, &tj);        edge[ti].push_back({tj, i});        edge[tj].push_back({ti, i});    }    if(di != -1)        dfs(di);    else if(sum & 1)    {        printf("-1\n");        return 0;    }    else        dfs(1);    printf("%d\n", ans.size() );    sort(ans.begin(), ans.end());    for(auto i : ans)        printf("%d ", i );    return 0;}

64行代码,重写时20分钟左右。
需要注意的是存在-1点的情况请从一个-1点开始dfs,否则会WA。
整理一下思路:先判断无解的情况,然后dfs大法好。
这道题好像能用树剖做,但是并不会,以后再学。

e题似乎是一个三维dp,先跳过,等div2 D稳了回来刷。

附 : cpp11的两个新特性

学习了C++11两个特性:auto和foreach。
auto在可以自动推断需要的变量类型,记不记得一长串的迭代器名字?
foreach就像java或者各种脚本语言中一样,按顺序遍历容器中的元素。
举两个栗子:

//自动推断i为int类型vector <int> ans; for(auto i : ans)         printf("%d ", i );
std::map<int,int> mp;mp[0]=1;std::map<int,int>::iterator pos;for(pos=mp.begin();pos!=mp.end();pos++)    printf("%d %d\n",pos->first,pos->second);//可简化为for(auto pos : mp)     printf("%d %d\n",pos.first,pos.second);
原创粉丝点击