Codeforces Round #375 (Div. 2)

来源:互联网 发布:mac下载器 编辑:程序博客网 时间:2024/05/17 05:51

只写了5题所以只说5题……

A
Task:
坐标轴上有三个点,求它们到坐标轴上某个点的距离和的最小值.

Solution:
显然只要选个最大值和一个最小值相减的差就是答案了,表示它们在中间相遇.
于是这题就不发代码了.


B
Task:
给你一个字符串,求括号内的单词数和括号外的最长单词长度,单词被括号(‘(‘,’)’)或下划线(‘_’)分割.

Solution:
也是一道比较水的题吧,只要一直算一下单词的长度,和它是否在括号内就行了.


C
Task:
给你一个序列,以及一个数字m,你能够改变序列中的数字,求使得序列中小于等于m的数出现次数最少的最多的次数,以及达到所需要的最少改变次数.

Solution:
题意理解错了,错了很多次…
想想就能知道第一个答案是n/m,第二个答案是i<=m,d[i]<n/mn/md[i],这里的d[i]指的是这个数出现过的次数.
然后就是怎么改的问题了,我们先把那些d[i]< n/m的放(n/m-d[i])个到队列里面,然后把那些可以被改的(大于m的数和数量大于n/m的数)下标放到队列里,然后一一选走就行了.

#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>#include<vector>#define M 2005using namespace std;vector<int>edge[M];int a[M],ned[M];int op[M];int main(){    int n,m;    int L=0,R=0,l=0,r=0;    scanf("%d %d",&n,&m);    int ans=n/m,cnt1=0;    for(int i=1;i<=n;i++){        scanf("%d",&a[i]);        if(a[i]<=m)edge[a[i]].push_back(i);        else op[r++]=i;    }    for(int i=1;i<=m;i++){        if(edge[i].size()<ans){            for(int j=1;j<=ans-edge[i].size();j++){                cnt1++;                ned[R++]=i;            }        }else if(edge[i].size()>ans){            for(int j=0;j<edge[i].size()-ans;j++){                op[r++]=edge[i][j];            }        }    }    while(L<R)a[op[l++]]=ned[L++];    printf("%d %d\n",ans,cnt1);    bool f=false;    for(int i=1;i<=n;i++){        if(f)putchar(' ');f=true;        printf("%d",a[i]);    }    puts("");    return 0;}

D
Task:
给你一张图,有水和陆地,与地图边缘的陆地相连的被称为海洋,否则称为湖,现在有一个k,最后要使湖的个数小于等于k,你可以填湖,求最后最少需填多少个点的湖,以及输出最后的一张图.

Solution:
只要在每一个点dfs一遍,去看看这个水是海洋还是湖,如果是湖,记录下湖的大小和坐标,最后按湖的大小排个序,取最小的几个填就行了.

#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>#define M 55using namespace std;char A[M][M];int n,m,k;int mark[M][M];bool im[M*M],mk[M][M];struct W{    int id,v;    bool operator<(const W &a)const{        return v<a.v;    }}Q[M*M];int rx[]={1,0,-1,0};int ry[]={0,-1,0,1};bool dfs(int x,int y){    if(x<1||x>n||y<1||y>m)return 0;    if(A[x][y]=='*')return true;    if(mk[x][y])return true;    mk[x][y]=true;    for(int i=0;i<4;i++)        if(!dfs(x+rx[i],y+ry[i]))return false;    return true;}int rdfs(int x,int y,int col){    if(x<1||x>n||y<1||y>m)return 0;    if(A[x][y]=='*')return 0;    if(mark[x][y])return 0;    mark[x][y]=col;    int re=1;    for(int i=0;i<4;i++)        re+=rdfs(x+rx[i],y+ry[i],col);    return re;}int main(){    scanf("%d %d %d",&n,&m,&k);    for(int i=1;i<=n;i++)scanf("%s",A[i]+1);    int sz=0,cnt=0;    for(int i=1;i<=n;i++)        for(int j=1;j<=m;j++){            if(!mark[i][j]&&A[i][j]=='.'){                if(dfs(i,j)){                    cnt++;                    Q[sz++]=(W){cnt,rdfs(i,j,cnt)};                }else rdfs(i,j,-1);            }        }    sort(Q,Q+sz);    int ans=0,ned=sz-k;    for(int i=0;i<ned;i++)        ans+=Q[i].v,im[Q[i].id]=1;    for(int i=1;i<=n;i++)        for(int j=1;j<=m;j++)            if(im[mark[i][j]])A[i][j]='*';    printf("%d\n",ans);    for(int i=1;i<=n;i++){        for(int j=1;j<=m;j++)            putchar(A[i][j]);        putchar('\n');    }    return 0;}

E
Task:
给你一个无向图,要你在对边定向后使得入度与出度相等的点最多,并输出边的定向(顺序任意).

Solution:
首先我们明确一个结论:
一张图内如果所有的点的度都是偶数,那么这张图对于每个连通块一定有一条欧拉回路,那么答案就是点的个数.
然后再有:
度为奇数的点一定不能使得出入度相等.
所以答案最多只能是这张图内度为偶数的点的个数.
接下来就是要构造出一组解,使得图内的偶点全部都是出入度相同.

现在就是下一个部分了
我们如果有一个度全为偶数的图,我们就能够构造出一条欧拉回路,所以考虑把奇点变成偶点,然后就构造欧拉回路就好了.
我们还可以知道奇点一定是偶数个的,因为如果奇点为奇数个,那么所有点的度之和一定是奇数,是不可能达到的.
这样,我们先处理出所有的奇点,再向图中加一个虚点,把奇点连一条边向这个虚点,使得图中只剩偶点,然后就可以用欧拉回路来算出每条边的定向了.

#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>#define M 205using namespace std;int u[M<<1][M<<1];bool mark[M<<1][M<<1];int ans[2][M*M],cnt[M],q[M];int n,m,tot=0;int ko;void dfs(int x){    for(int i=1;i<=ko;i++){        if(u[x][i]){            u[x][i]--;            u[i][x]--;            if(mark[x][i]){                ans[0][tot]=x;                ans[1][tot]=i;tot++;            }            mark[x][i]=mark[i][x]=0;            dfs(i);        }    }}int main(){    int cas;    scanf("%d",&cas);    while(cas--){        memset(cnt,0,sizeof(cnt));        memset(u,0,sizeof(u));        memset(mark,0,sizeof(mark));        tot=0;        scanf("%d %d",&n,&m);        for(int i=1;i<=m;i++){            int x,y;            scanf("%d %d",&x,&y);            u[x][y]++;            u[y][x]++;            cnt[x]++;            cnt[y]++;            mark[x][y]=mark[y][x]=1;        }        int pl=0,sz=0;        for(int i=1;i<=n;i++)            if(cnt[i]&1){                q[sz++]=i;            }else pl++;        ko=n;        for(int i=0;i<sz;i+=2){            u[q[i]][++ko]=1;            u[ko][q[i]]=1;            u[ko][q[i+1]]=1;            u[q[i+1]][ko]=1;        }        printf("%d\n",pl);        for(int i=1;i<=n;i++)dfs(i);        for(int i=0;i<m;i++)            printf("%d %d\n",ans[0][i],ans[1][i]);    }    return 0;}

PS:这道题目比赛时差点就A了,就是最后差了一点,没有想到构造一个虚点,而是想在两个奇点之间连线(虽然也差不多,可是细节很麻烦).然后就没写出来…

1 0