zoukankan      html  css  js  c++  java
  • 【Codeforces】Round #543 (Div 2) 解题报告

    前言:今天改题时结识了FlyWhite学长,下午与他聊了许久。近来生活充斥着各种不确定因素,真的是不能飘啊。学长建议我每场cf都打,把所有的题都补完并且写题解,所以就拿前天改完的Round #543来开刀吧。

    对自己的吐槽:还是一如既往地只在ABC徘徊,数组又开小了...并且没有做出C... 

    Problem A. Technogoblet of Fire


    题目大意:有n个人来自k个学校,告诉你n个人的能力。现在每个学校派出最强的那个人去参赛。但是现在要求有m个人必须要参赛,但他们可能不是自己学校最强的,可以把他们放进新学校里。问最少的新学校数目。

    数据范围:所有数字均在100以内

    根据题意先保存每个学校最强的人的能力是多少,然后对每一个人判断他是不是最强的那个,不是就++ans

    代码:不贴了。

    Problem B. Mike and Children


    题目大意:Mike有n个大小不同的糖果,现在Mike决定给一些孩子每个人2个糖果,如果孩子们拿到的2个糖果大小的和不相同,孩子们就会不开心。现在问Mike最多可以使多少个孩子开心。

    数据范围:1≤n≤1000,1≤糖果大小≤105

    因为大小不同,所以每一个糖果和其他n-1个糖果一共可以得到n-1个大小, O(N2)计算所有的结果放在一个桶中,取最大值。

    代码:不贴了。

    Problem C. System Testing


    题目大意:有一台评测机,同一时刻可以评测k个程序,评测每个程序的1个样例需要1s。给出n个程序的样例数(运行时间),测完一个就测下一个。定义一个程序是“有趣的”当这个程序在评测第x个样例时,系统显示评测进度为x%。求有趣的程序的数量。

    系统评测进度的计算方法:已评测程序数/总程序数*100 四舍五入。

    数据范围:1≤n≤1000,1≤k≤100,1≤每个程序的样例数≤150

    题意比较简单,但是代码不太好写(码力不足请充值)。数据范围较小,所以可以考虑安照时间来1s 1s地做。

    代码:

     1 #include<stdio.h>
     2 
     3 const int N=1050;
     4 const int K=150;
     5 
     6 int n,k,ans=0;
     7 int cnt,dcnt,d;
     8 int a[N];
     9 struct task{
    10     int num,time;
    11 }p[N];
    12 bool vis[N];
    13 
    14 int main(){
    15     scanf("%d%d",&n,&k);
    16     for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    17     while(dcnt<n){
    18         for(int i=1;i<=k;i++){
    19             if(p[i].num==0||p[i].time==a[p[i].num]){
    20                 if(p[i].num)++dcnt;
    21                 if(cnt<n){
    22                     p[i].num=++cnt;
    23                     p[i].time=1;
    24                 }
    25                 else p[i].num=0;
    26             }
    27             else ++p[i].time;
    28         }
    29         d=(int)((double)100*dcnt/n+0.5);
    30         for(int i=1;i<=k;i++)if(p[i].time==d)vis[p[i].num]=1;
    31     }
    32     for(int i=1;i<=n;i++)ans+=vis[i];
    33     printf("%d",ans);
    34     return 0;
    35 }
    ~

    Problem D. Diana and Liana


    题目大意:现在有一条藤蔓,上面有k种花,共m朵。有一台机器可以把每k朵花做成一个花环,当藤蔓上花不足k朵是就停止工作不再制造花环了。有n个人需要n个花环。但是其中一个人想要自己指定的s朵花做成的花环(其他的n-1个人不在乎自己的花环长啥样,有花环就行了),他可以从藤蔓上去掉一些花使藤蔓的某一段刚好具有他想要的s朵花并且被做成一个花环。现在求他需要去掉多少朵花,是哪些花。

    花环上花的顺序无关紧要,

    数据范围:1≤n,k,m≤5*105,k*n≤m,1≤s≤k

    我们先计算出最多可以去掉的花数量d,在一个k+d的区间内统计k种花的数量看看有没有我们需要的那s朵,如果有就暴力算出可以去掉的花的下标,否则我们跳到下一个区间[k*i+1,k*i+k+d],并且再次统计各种花的数量,判断是否符合条件。利用一个类似莫队的方法,把区间k个k个单位的移动,把区间外的“吐”掉,再把区间内的“吃”掉。时间复杂度O(N),每朵花只被计算一次。

    代码:

     1 #include<stdio.h>
     2 #include<algorithm>
     3 using namespace std;
     4 const int N=500050;
     5 
     6 int m,k,n,s;
     7 int a[N],b[N];
     8 int len;
     9 int cnt[N],ok;
    10 struct node{
    11     int v,pos;
    12     bool operator <(const node _)const{
    13         return v<_.v;
    14     }
    15 }c[N];
    16 bool vis[N];
    17 int main(){
    18     scanf("%d%d%d%d",&m,&k,&n,&s);
    19     for(int i=1;i<=m;i++)scanf("%d",&a[i]);
    20     for(int i=1;i<=s;i++)scanf("%d",&b[i]),--cnt[b[i]];
    21     for(int i=1;i<=N;i++)if(cnt[i]<0)++ok;
    22     len=m-n*k;
    23     len+=k;
    24     int l=0,r=0,p=0,t;
    25     int ll=0,rr=0;
    26     while(p*k+len<=m){
    27         ll=l; rr=r;
    28         l=p*k+1; r=p*k+len;
    29         t=min(l-1,rr);
    30         for(int i=ll;i<=t;i++){
    31             if(!i)continue;
    32             --cnt[a[i]];
    33             if(cnt[a[i]]==-1)++ok;
    34         }
    35         t=max(l,rr+1);
    36         for(int i=t;i<=r;i++){
    37             ++cnt[a[i]];
    38             if(cnt[a[i]]==0)--ok;
    39         }
    40         ++p;
    41         if(ok==0){
    42             len-=k;
    43             printf("%d\n",len);
    44             if(!len)return 0; 
    45             for(int i=l;i<=r;i++)c[i]=(node){a[i],i};
    46             sort(b+1,b+s+1);
    47             sort(c+l,c+r);
    48             int pb=1,pc=l;
    49             while(1){
    50                 if(c[pc].v!=b[pb]){printf("%d ",c[pc].pos); --len; ++pc;}
    51                 if(len==0)return 0;
    52                 if(c[pc].v==b[pb]){++pc,++pb;}
    53             }
    54             return 0;
    55         }
    56     }
    57     printf("-1");
    58     return 0;
    59 }
    ~

    Problem E. Once in a casino


    题目大意:对一个长度为n的数字a,我们可以对他的相邻两位(i&i+1,1<=i<n)加1或者减1。0不能减1,9不能加1。求数字a能不能通过操作变成数字b,并且输出方案(步数大于1×105就只输出前1×105步)

    数据范围:2≤n≤105

    官方公告:由于技术原因此题可能比F题要难...

    贪心,从最边上开始,如果现在这位比b小就++,比b大就--,相邻的那一为逢0就加,逢9就减。如此递归,同时记录方案。

    然后再算一遍,相同的方法,不过不需要记录步数了,还有些细节需要处理。

    代码:

     1 #include<stdio.h>
     2 #include<string.h>
     3 #include<iostream>
     4 using namespace std;
     5 const int N=100050;
     6 
     7 int n;
     8 char s[N];
     9 int a[N],b[N],x[N],y[N];
    10 int cnt;
    11 long long ans;
    12 struct step{
    13     int k,d;
    14 }st[N*10];
    15 
    16 int min(int _,int __){return _<__?_:__;}
    17 void over(){
    18     printf("-1");
    19     exit(0);
    20 }
    21 void add(int i);
    22 void sub(int i);
    23 void add(int i){
    24     if(i==n)over();
    25     if(a[i+1]==9)sub(i+1);
    26     st[++cnt]=(step){i,1};
    27     ++a[i]; ++a[i+1];
    28 }
    29 void sub(int i){
    30     if(i==n)over();
    31     if(a[i+1]==0)add(i+1);
    32     st[++cnt]=(step){i,-1};
    33     --a[i]; --a[i+1];
    34 }
    35 int main(){
    36     scanf("%d",&n);
    37     scanf("%s",s+1);
    38     for(int i=1;i<=n;i++)a[i]=x[i]=s[i]-'0';
    39     scanf("%s",s+1);
    40     for(int i=1;i<=n;i++)b[i]=y[i]=s[i]-'0';
    41     for(int i=1;i<n;i++){
    42         while(a[i]<b[i]&&cnt<1e5)add(i);
    43         while(a[i]>b[i]&&cnt<1e5)sub(i);
    44     }
    45     int t;
    46     for(int i=1;i<n;i++){
    47         if(x[i]<0){
    48             t=-x[i];
    49             ans+=t;
    50             x[i]+=t; x[i+1]+=t;
    51         }
    52         if(x[i]>9){
    53             t=x[i]-9;
    54             ans+=t;
    55             x[i]-=t; x[i+1]-=t;
    56         }
    57         while(x[i]<y[i])++x[i],++x[i+1],++ans;
    58         while(x[i]>y[i])--x[i],--x[i+1],++ans;
    59     }
    60     if(x[n]!=y[n])over();
    61     printf("%I64d\n",ans);
    62     for(int i=1;i<=min(cnt,100000);i++){
    63         printf("%d %d\n",st[i].k,st[i].d);
    64     }
    65     return 0;
    66 }
    ~

    Problem F. Compress String


    题目大意:有一个长度为n的字符串S,可以把其划分成若干字串:S->t1t2t3...tk-1tk啊,对于每一个字串ti的划分代价是

    ·若ti长度为1,代价为a

    ·若ti是t1t2t3...ti-1ti的字串,代价为b

    求字符串的最小划分代价。

    数据范围:1≤n,a,b≤5000

    暴力求出每个位置i上以i结尾的字符串是前面字符串的字串长度最大是多少,然后dp即可。

    代码:

     1 #include<stdio.h>
     2 #include<iostream>
     3 using namespace std;
     4 
     5 const int N=5050;
     6 
     7 int n,a,b;
     8 int f[N];
     9 char s[N];
    10 int z[N];
    11 
    12 int zfunc(int t)
    13 {
    14     int ans=0;
    15     z[t]=0;
    16     int l=n+1;
    17     int r=n+1;
    18     for(int i=t-1;i>=1;i--)
    19     {
    20         z[i]=0;
    21         if(r<=i)z[i]=min(i-r+1,z[t-l+i]);
    22         while(i-z[i]>0&&s[i-z[i]]==s[t-z[i]])
    23         z[i]++;
    24         if(z[i]&&i-z[i]<r)r=i-z[i]+1,l=i;
    25         ans=max(ans,min(z[i],t-i));
    26     }
    27     return    ans;
    28 }
    29 
    30 int    main(){
    31     scanf("%d%d%d",&n,&a,&b);
    32     scanf("%s",s+1);
    33     f[1]=a;
    34     for(int i=2;i<=n;i++)
    35     {
    36         int lng=zfunc(i);
    37         f[i]=f[i-1]+a;
    38         if(lng)f[i]=min(f[i],f[i-lng]+b);
    39     }
    40     printf("%d",f[n]);
    41     return 0;
    42 }
    ~
  • 相关阅读:
    Java正则表达式的使用
    萤火虫小巷2(看完了)
    第七章--Java基础类库--与用户的互动
    Android界面编程--使用活动条(ActionBar)--通过ActionBar菜单改变TextView的字体和颜色
    电影:换肤(Replace)
    Android界面编程--使用活动条(ActionBar)
    萤火虫小巷1
    大三下半学期(3月4日定下的学习计划)
    12月17日问题
    JQuery 分页显示jquery-pager-1.0.js
  • 原文地址:https://www.cnblogs.com/opethrax/p/10492938.html
Copyright © 2011-2022 走看看