Codeforces Round #513 by Barcelona Bootcamp (rated, Div. 1 + Div. 2)

A.Phone Numbers

题意:给你n个数字,每个数字最多只能用一次,问你最多能组成以8开头的11位电话号码有多少个

思路:模拟即可,注意char数组读入是从0下标开始的(在这里被hack了...)

 1 #include<bits/stdc++.h>
 2 int main()
 3 {
 4     int n,num=0,ans=0;
 5     char c[105];
 6     scanf("%d%s",&n,c);
 7     for(int i=0;i<n;i++)if(c[i]=='8')num++;//原来是从1到n... 
 8     while(num>0&&n>=11)
 9     {
10         num--;
11         n-=11;
12         ans++;
13     }
14     printf("%d\n",ans);
15     return 0;
16 }
View Code

B. Maximum Sum of Digits

题意:设正整数a,b和为n,现给定n,求每位数字和最大的一组(a,b),这个和为多少

思路:由于是求每位数字的和,所以具体地考虑对一个具体数位的分割,发现对于一个确定的数ai,无论怎样分,是否借位/被借位,其和都是ai,而对于不同分法产生差异的原因在于是否借位

  由此可以记忆化dfs,设f(id,bor,Now)表示到第id位,是否被借位(0,1),当前数码和为Now

  要注意借位与不借位情况的判定(原来来少考虑了没有借位过的9不能借位,被hack了)

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int ans=0,a[15]={0};
 4 int Mark[15][5][255]={0};
 5 int dfs(int id,int bor,int Now)
 6 {
 7     if(id==a[0]+1)
 8     {
 9         ans=max(ans,Now);
10         return ans;
11     }
12     
13     if(Mark[id][bor][Now]!=-1)return Mark[id][bor][Now];
14     
15     int tmp=0;
16     if(a[id]!=0)tmp=max(tmp,dfs(id+1,0,Now+a[id]-bor));
17     //µ±Ç°Î»²»ÎªÁãÔò¿¼ÂDz»ÏòÏÂһλ½èλµÄÇé¿ö£¨Îª0Ôò½èλ±ØÈ»¸üÓÅ£¬ÇÒ°üº¬Á˱»½èλµÄÇé¿ö£© 
18     if(id!=a[0]&&(!(a[id]==9&&bor==0)))tmp=max(tmp,dfs(id+1,1,Now+a[id]+10-bor));
19     //¸ÃλÖò»Îª×î¸ßλÇÒ²»ÎªÃ»±»½èλ¹ýµÄ9£¬Ôò¿¼ÂÇÏòÏÂһλ½èλ 
20     //Ô­À´ÉÙ¿¼ÂÇÁËûÓнèλ¹ýµÄ9²»Äܽèλ 
21     
22     return Mark[id][bor][Now]=tmp;
23 }
24 int main()
25 {
26     long long n;
27     scanf("%lld",&n);
28     while(n)
29     {
30         a[++a[0]]=n%10;
31         n/=10;
32     }
33     memset(Mark,-1,sizeof(Mark));
34     dfs(1,0,0);
35     printf("%d\n",ans);
36     return 0;
37 }
View Code

C. Maximum Subrectangle

题意:给定长度为n的数组a和长度为m的数组b,求满足ai*bj<=x(其中i从x1变化到x2,j从y1变化到y2)的使x1,x2,y1,y2表示的矩形的最大面积

思路:先化简式子,可以把限制条件化简为(sa2-sa1)*(sb2-sb1)<=x,考虑到a和b都是长为2000的数组,把这四个前缀和都枚举一遍肯定是不行的

  这时可以用贪心的思想,我们只需要求得同一个数组在相同长度下前缀和之差的最小值即可,然后再把(sa2-sa1)*(sb2-sb1)的两个乘法因子分别按照顺序和倒序进行枚举即可

  这样做的时间复杂度使o(n^2)

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int sa[2005]={0},sb[2005]={0},fa[2005]={0},fb[2005]={0};
 4 int main()
 5 {
 6     int n,m,tmp,x;
 7     scanf("%d%d",&n,&m);
 8     for(int i=1;i<=n;i++)
 9     {
10         scanf("%d",&tmp);
11         sa[i]=sa[i-1]+tmp;
12         fa[i]=1e9;
13     }
14     for(int i=1;i<=m;i++)
15     {
16         scanf("%d",&tmp);
17         sb[i]=sb[i-1]+tmp;
18         fb[i]=1e9;
19     }
20     scanf("%d",&x);
21     
22     for(int i=1;i<=n;i++)
23     for(int j=i;j<=n;j++)fa[j-i+1]=min(fa[j-i+1],sa[j]-sa[i-1]);
24     
25     for(int i=1;i<=m;i++)
26     for(int j=i;j<=m;j++)fb[j-i+1]=min(fb[j-i+1],sb[j]-sb[i-1]);
27     
28     int i=1,j=m,ans=0;
29     while(i<=n&&j>=1)
30     {
31         if(fa[i]<=x/fb[j])
32         {
33             ans=max(ans,i*j);
34             i++;    
35         }
36         else j--;
37     }
38     
39     printf("%d\n",ans);
40     return 0;
41 }
View Code

 

D. Social Circles

题意:n个人摆宴席,每个人左边和右边都分别至少有li和ri个空位,桌子的个数不限,也可以一个人一桌,求最少的板凳数

思路:当时察觉到了是贪心算法,但并没有想出来

  看了别人的代码是把l,r读入后分别排序,按小小对应,大大对应的规则直接求出答案

  在这里验证一下正确性:

  1. 只考虑两个人,设其属性为(l,r)和(l',r'),且有l' > l和r' < r,那么max(l’,r’)+max(l,r)一定不小于max(l’,r)+max(l,r’),(可以画图验证),且必然对应了一种摆桌方案
  2. 考虑n个人,如果有两个人没有满足小小对应,大大对应,那么他们交换了之后一定会更优,这就证明了读入后直接排序的正确性
  3. 而对于这样的配对方案,又一定存在一种摆桌方案,证明:设(ai,bj)为某人的属性,若ai=bj则自己围一桌即可,否则,必有另一人(aj,bk)与其右边合并,这样就可以把这两个人看做一个人(ai,bk)...这样一直合并,最后一定可以合并成(ai,bi)
  4. 综上,这样的贪心算法是正确的

转载于:https://www.cnblogs.com/hitsz-crz/p/9743874.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值