Codeforces Round #311 (Div. 2) A~E && DE题解

来源:互联网 发布:如何在淘宝上开好网店 编辑:程序博客网 时间:2024/05/07 16:41

A Ilya and Diplomas
Problem Description:

Soon a school Olympiad in Informatics will be held in Berland, n schoolchildren will participate there.

At a meeting of the jury of the Olympiad it was decided that each of the n participants, depending on the results, will get a diploma of the first, second or third degree. Thus, each student will receive exactly one diploma.

They also decided that there must be given at least min1 and at most max1 diplomas of the first degree, at least min2 and at most max2 diplomas of the second degree, and at least min3 and at most max3 diplomas of the third degree.

After some discussion it was decided to choose from all the options of distributing diplomas satisfying these limitations the one that maximizes the number of participants who receive diplomas of the first degree. Of all these options they select the one which maximizes the number of the participants who receive diplomas of the second degree. If there are multiple of these options, they select the option that maximizes the number of diplomas of the third degree.

Choosing the best option of distributing certificates was entrusted to Ilya, one of the best programmers of Berland. However, he found more important things to do, so it is your task now to choose the best option of distributing of diplomas, based on the described limitations.

It is guaranteed that the described limitations are such that there is a way to choose such an option of distributing diplomas that all n participants of the Olympiad will receive a diploma of some degree.

#include<stdio.h>#include<string.h>#include<iostream>#include<algorithm>#include<math.h>#include<vector>#include<map>#include<set>using namespace std;int main(){    int n,m1[3],m2[3],sum,i;    while(~scanf("%d",&n))    {        sum=0;         for(i=0;i<3;i++)        scanf("%d%d",&m1[i],&m2[i]);        sum+=m1[0]+m1[1]+m1[2];        n-=sum;        //printf("%d %d %d\n",m1[0],m1[1],m1[2]);        if(n)        {            for(i=0;i<=2;i++)            if(n>=m2[i]-m1[i])            {                n-=m2[i]-m1[i];                m1[i]=m2[i];            }            else            {                m1[i]+=n;                n=0;            }        }        printf("%d %d %d\n",m1[0],m1[1],m1[2]);    }}

B. Pasha and Tea
Problem Description:
Pasha decided to invite his friends to a tea party. For that occasion, he has a large teapot with the capacity of w milliliters and 2n tea cups, each cup is for one of Pasha’s friends. The i-th cup can hold at most ai milliliters of water.

It turned out that among Pasha’s friends there are exactly n boys and exactly n girls and all of them are going to come to the tea party. To please everyone, Pasha decided to pour the water for the tea as follows:

Pasha can boil the teapot exactly once by pouring there at most w milliliters of water;
Pasha pours the same amount of water to each girl;
Pasha pours the same amount of water to each boy;
if each girl gets x milliliters of water, then each boy gets 2x milliliters of water.
In the other words, each boy should get two times more water than each girl does.

Pasha is very kind and polite, so he wants to maximize the total amount of the water that he pours to his friends. Your task is to help him and determine the optimum distribution of cups between Pasha’s friends.

#include<stdio.h>#include<string.h>#include<iostream>#include<algorithm>#include<math.h>#include<vector>#include<map>#include<set>using namespace std;double s[200005];int main(){    double w;    int i,n;    while(~scanf("%d%lf",&n,&w))    {        for(i=1;i<=n*2;i++)        scanf("%lf",&s[i]);        sort(s+1,s+n*2+1);        double ans=w;        if(s[1]*2<=s[n+1])        ans=min(ans,s[1]*n*3);        else ans=min(ans,s[n+1]*n*1.5);        printf("%.6lf\n",ans);    }}

C. Arthur and Table
Problem Description:
Arthur has bought a beautiful big table into his new flat. When he came home, Arthur noticed that the new table is unstable.

In total the table Arthur bought has n legs, the length of the i-th leg is li.

Arthur decided to make the table stable and remove some legs. For each of them Arthur determined number di — the amount of energy that he spends to remove the i-th leg.

A table with k legs is assumed to be stable if there are more than half legs of the maximum length. For example, to make a table with 5 legs stable, you need to make sure it has at least three (out of these five) legs of the maximum length. Also, a table with one leg is always stable and a table with two legs is stable if and only if they have the same lengths.

Your task is to help Arthur and count the minimum number of energy units Arthur should spend on making the table stable.
思路:
针对di<=200就KO了

/*思路:针对di<=200就KO了 */ #include<stdio.h>#include<string.h>#include<iostream>#include<algorithm>#include<math.h>#include<queue>#include<stack>#include<string>#include<vector>#include<map>#include<set>using namespace std;#define lowbit(x) (x&(-x))typedef long long LL;const int maxn = 100005;const int inf=(1<<28)-1;struct node{    int l,d;}A[maxn];int num[205];bool cmp(node u,node v){    return u.l>v.l;}int main(){    int n;    scanf("%d",&n);    for(int i=1;i<=n;++i)    scanf("%d",&A[i].l);    for(int i=1;i<=n;++i)    {        scanf("%d",&A[i].d);        num[A[i].d]++;    }    sort(A+1,A+n+1,cmp);    LL res=0,ans=inf;    for(int i=1;i<=n;++i)    {        //printf("%d\n",res);        int cnt=0,flag;        for(int j=i;j<=n;++j)        {            flag=j;            if(A[i].l==A[j].l) cnt++;            else break;            if(j==n) flag++;        }        int now=0;        for(int j=i;j<flag;++j)        {            now+=A[j].d;            num[A[j].d]--;            i=j;        }        if(cnt>n-flag+1)         {            ans=min(ans,res);            continue;        }        int x=n-flag+1-cnt+1,tmp=0;        //printf("i=%d %d\n",i,x);        for(int j=0;j<=200;++j)        if(num[j]>x)        {            tmp+=x*j;            break;        }        else        {            tmp+=num[j]*j;            x-=num[j];        }        ans=min(ans,res+tmp);        res+=now;    }    printf("%d\n",ans);     return 0;}

D. Vitaly and Cycle
Problem Description:
After Vitaly was expelled from the university, he became interested in the graph theory.

Vitaly especially liked the cycles of an odd length in which each vertex occurs at most once.

Vitaly was wondering how to solve the following problem. You are given an undirected graph consisting of n vertices and m edges, not necessarily connected, without parallel edges and loops. You need to find t — the minimum number of edges that must be added to the given graph in order to form a simple cycle of an odd length, consisting of more than one vertex. Moreover, he must find w — the number of ways to add t edges in order to form a cycle of an odd length (consisting of more than one vertex). It is prohibited to add loops or parallel edges.

Two ways to add edges to the graph are considered equal if they have the same sets of added edges.

Since Vitaly does not study at the university, he asked you to help him with this task.
题意:给n个点和m条边,无自连和重边
求最少加几条边形成奇圈(边数为奇数的圈)和有多少种方法
思路:
很容易想到答案有0 1 2 3这三种情况
由于是奇圈,所以很容易想到用关于二分图什么的
然后就想到用染色法,在同一条链上如果两个颜色相同的点相连一定是奇圈(Ans=0)
所以很容易染色的时候找有没有相同颜色连一起,统计一下(Ans=1)
如果链的长度>=3的时候一定可以通过连一条边来形成奇圈
但是不是ChainLen-2,因为比如
5 4
1-2 1-3 1-4 1-5这种情况就比较尴尬了
所以答案应该是找颜色为0的点个数和1的点的个数
然后这两个点相连就OK了,统计就是C(NumColor,2)
如果只有长度为2的链,那么随便找个点连一连就OK了
(Ans=2)+(n-2)
如果图上没边的话就比较好统计了(Ans=3)
跑个for来枚举一个点,然后剩下的点任意选两个

#include<stdio.h>#include<string.h>#include<iostream>#include<algorithm>#include<math.h>#include<queue>#include<stack>#include<string>#include<vector>#include<map>#include<set>using namespace std;#define lowbit(x) (x&(-x))typedef long long LL;const int maxn = 100005;const int inf=(1<<28)-1;vector<int>vec[maxn];LL Ans[4];int Color[maxn],ChainLen;LL NumColor0,NumColor1;void dfs(int u,int fa){    if(1==Color[u]) NumColor1++;    else NumColor0++;    int Size=vec[u].size();    ChainLen++;    for(int i=0;i<Size;++i)    {        int v=vec[u][i];        if(v==fa) continue;        if(-1!=Color[v])        {            if(Color[v]==Color[u]) Ans[0]++;        }        else         {            Color[v]=!Color[u];            dfs(v,u);        }    }}int main(){    int n,m;    scanf("%d%d",&n,&m);    for(int i=1;i<=m;++i)    {        int u,v;        scanf("%d%d",&u,&v);        vec[u].push_back(v);        vec[v].push_back(u);    }    memset(Color,-1,sizeof(Color));    for(int i=1;i<=n;++i)    if(-1==Color[i])    {        ChainLen=0;        Color[i]=0;        NumColor1=NumColor0=0;        dfs(i,i);        if(ChainLen>=3)        {            if(NumColor1>=2) Ans[1]+=NumColor1*(NumColor1-1)/2;            if(NumColor0>=2) Ans[1]+=NumColor0*(NumColor0-1)/2;        }        else if(ChainLen==2)        {            Ans[2]+=n-2;        }    }    for(int i=1;i+2<=n;++i)    {        Ans[3]+=((LL)(n-i)*(n-i-1))/2;    }    Ans[0]/=2;    for(int i=0;i<4;++i)    if(Ans[i])    {        printf("%d %lld\n",i,Ans[i]);        return 0;    }    return 0;}

E. Ann and Half-Palindrome
Problem Description:
Tomorrow Ann takes the hardest exam of programming where she should get an excellent mark.

On the last theoretical class the teacher introduced the notion of a half-palindrome.

String t is a half-palindrome, if for all the odd positions i () the following condition is held: ti = t|t| - i + 1, where |t| is the length of string t if positions are indexed from 1. For example, strings “abaa”, “a”, “bb”, “abbbaa” are half-palindromes and strings “ab”, “bba” and “aaabaa” are not.

Ann knows that on the exam she will get string s, consisting only of letters a and b, and number k. To get an excellent mark she has to find the k-th in the lexicographical order string among all substrings of s that are half-palyndromes. Note that each substring in this order is considered as many times as many times it occurs in s.

The teachers guarantees that the given number k doesn’t exceed the number of substrings of the given string that are half-palindromes.

Can you cope with this problem?
题意:找一个串所有子串中的第k大半回文串
半回文串的意思就是第奇数个字母等于倒数第奇数个字母
思路:
就是先dp,dp[i][j]是长度为i,从j开始的串是不是半回文串
然后向字典树里插以每个点开始的最长的半回文串,插最长的时候就可以插<=最长的半回文串
然后就KO

#include<stdio.h>#include<string.h>#include<iostream>#include<algorithm>#include<math.h>#include<queue>#include<stack>#include<string>#include<vector>#include<map>#include<set>using namespace std;#define lowbit(x) (x&(-x))typedef long long LL;const int maxn = 5005;const int maxm = 15502500;const int inf=(1<<28)-1;bool dp[maxn][maxn];int ch[maxm][2],Sum[maxm],tot=1,Cur[maxm];int Ans=0;void Insert(char* str,int l,int r){    int p=1;    Ans++;    for(int i=l;i<=r;++i)    {        int id=str[i]-'a';        if(-1==ch[p][id])         {            ch[p][id]=++tot;        }        p=ch[p][id];        if(dp[i-l+1][l]) Cur[p]++;    }}void dfs(int u){       Sum[u]+=Cur[u];    if(ch[u][0])     {        dfs(ch[u][0]);        Sum[u]+=Sum[ch[u][0]];    }    if(ch[u][1])     {        dfs(ch[u][1]);        Sum[u]+=Sum[ch[u][1]];    }}void find(int k){    int p=1;    while(k)    {        k-=Cur[p];        if(0>=k) return ;        if(Sum[ch[p][0]]>=k)        {            printf("a");            p=ch[p][0];        }        else        {            printf("b");            k-=Sum[ch[p][0]];            p=ch[p][1];        }    }}void print_root(int u){    printf("%d %d %d: ",u,Sum[u],Cur[u]);    printf("lson:%d(%d) ",ch[u][0],Sum[ch[u][0]]);    printf("rson:%d(%d) \n",ch[u][1],Sum[ch[u][1]]);    if(-1!=ch[u][0])    print_root(ch[u][0]);    if(-1!=ch[u][1])    print_root(ch[u][1]);}char str[maxn];int main(){    int k;    scanf("%s%d",str,&k);    int len=strlen(str);    for(int i=0;i<len;++i) dp[0][i]=dp[1][i]=true;    for(int i=2;i<=len;++i)    {        for(int j=0;j+i-1<len;++j)        {            int Sta=j,End=i+j-1;            if(str[Sta]==str[End])            {                if(Sta+2>=End-2) dp[i][j]=true;                else dp[i][j]=dp[i-4][Sta+2];            }            else dp[i][j]=false;        }    }    memset(ch,-1,sizeof(ch));    for(int i=0;i<len;++i)    {        for(int j=len-i;j>0;--j)        if(dp[j][i])        {            Insert(str,i,i+j-1);            break;        }    }    dfs(1);    //print_root(1);    find(k);printf("\n");    return 0;}
0 0