zoukankan      html  css  js  c++  java
  • [Codeforces]Codeforces Round #538 (Div. 2)

    A - Got Any Grapes?  

    题意

    Andrew, Dmitry and Michal想要吃葡萄。

    Andrew只吃绿葡萄。Dmitry不吃黑葡萄。Michal吃嘛嘛香。

    他们分别吃$x,y,z$个葡萄,绿,紫,黑葡萄分别有$a,b,c$个。

    问能不能满♂足他们。

    分析

    Andrew只吃绿的,那么先给他吃,然后把看看除了黑葡萄外的葡萄能不能满足Michal,剩下的再给Dmitry。

    代码

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 int read(){
     4     char c;int num,f=1;
     5     while(c=getchar(),!isdigit(c))if(c=='-')f=-1;num=c-'0';
     6     while(c=getchar(), isdigit(c))num=num*10+c-'0';
     7     return f*num;
     8 }
     9 int a[10],b[10];
    10 int main()
    11 {
    12     for(int i=1;i<=3;i++)a[i]=read();
    13     for(int i=1;i<=3;i++)b[i]=read();
    14     if(a[1]<=b[1]){
    15         a[1]-=b[1];
    16         b[1]=0;
    17         if(a[1]+a[2]<=b[2]){
    18             int del=min(a[1],b[2]);
    19             a[1]-=del;b[2]-=del;
    20             a[2]-=b[2];b[2]=0;
    21             //cout<<1<<endl;
    22             if(a[1]+a[2]+a[3]<=b[3]){
    23                 printf("YES
    ");
    24                 return 0;
    25             }
    26         }
    27     }
    28     printf("NO
    ");
    29     return 0;
    30 }
    View Code

     

    B - Yet Another Array Partitioning Task

    题意

    定义一个序列的美丽值为这个数前$m$大的数之和,给定一个序列,要求把他划分成$k$段,求美丽值之和最大是多少,并输出方案。

    分析

    理性分析一波,一个序列里面我们要取$k imes m$个元素,求这些元素之和的最大值。

    怎么能取到最大呢?

    这些元素恰好是所有序列里面前$k imes m$大就行了。

    这样能不能取到呢?

    显然是可以的,我们给数组排序,标记出所有前$k imes m$大元素,然后我们每取到$m$个标记元素划分一段,就可以了。

    代码

     1 #include <bits/stdc++.h>
     2 #define ll long long
     3 using namespace std;
     4 const int N=5e5+1009;
     5 struct node{int val,pos;}a[N];
     6 int read(){
     7     char c;int num,f=1;
     8     while(c=getchar(),!isdigit(c))if(c=='-')f=-1;num=c-'0';
     9     while(c=getchar(), isdigit(c))num=num*10+c-'0';
    10     return f*num;
    11 }
    12 bool cmp(node a,node b){return a.val>b.val;}
    13 int f[N],n,m,k,tmp=0,cnt=0;
    14 ll sum;
    15 int main()
    16 {
    17     n=read();m=read();k=read();
    18     for(int i=1;i<=n;i++){
    19         a[i].val=read();
    20         a[i].pos=i;
    21     }
    22     sort(a+1,a+1+n,cmp);
    23     for(int i=1;i<=m*k;i++){
    24         f[a[i].pos]=1;
    25         sum+=a[i].val;
    26     }
    27     cout<<sum<<endl;
    28     for(int i=1;i<=n;i++){
    29         tmp+=f[i];
    30         if(cnt==k-1)break;
    31         if(tmp>=m)tmp=0,cout<<i<<" ",cnt++;
    32     }
    33     cout<<endl;
    34     return 0;
    35 }
    View Code

     

    C - Trailing Loves (or L'oeufs?)

    题意

    求$n!$在$b$进制下末尾$0$的个数。

    分析

    先考虑进制转换后的末尾$0$是怎么产生的,我们进制转换就是把一个数$n!$不断除以$b$,然后倒序输出余数。

    末尾$0$就是一开始的一长串$0$也就是$n!$能整除的$b$的个数。

    然后我们把问题转化为了$n!$分解质因数之后能配成多少对$b$的质因数。

    假设说$n!=3*3*2*2*2,b=2*3$(只是假设,不关心能不能取到)。

    那么我们能组成两对$b$,也就是说取这个$b$最小的一个质因数在$n!$中的个数。

    注意某个质因数有多个的话$n!$中对应质因数要均分。

    一个质因数在$n!$中有多少个呢?

    容斥一下应该是$frac{n}{b}+frac{n}{b^2}+frac{n}{b^3}+...$

    那么就很好算了,我们求出每个因数的个数,然后取最小值就没问题了。

    (这种题我居然写了40多分钟,退役算了)

    代码

     1 #include <bits/stdc++.h>
     2 #define ll long long
     3 using namespace std;
     4 const int N=1e6+1009;
     5 int cnt;
     6 ll num[N],n,b,minn=-1,nn[N];
     7 int main()
     8 {
     9     cin>>n>>b;
    10     for(int i=2;i<=sqrt(b);i++){
    11         if(b%i)continue;
    12         num[++cnt]=i;b/=i;
    13         nn[cnt]=1;
    14         while(b%i==0){
    15             nn[cnt]++;
    16             b/=i;
    17         }
    18     }
    19     if(b>1)num[++cnt]=b,nn[cnt]=1;
    20     for(int i=1;i<=cnt;i++){
    21         ll tmp=n,sum=0;
    22         while(tmp){
    23             sum+=tmp/num[i];
    24             tmp/=num[i];
    25         }
    26         if(minn==-1)minn=sum/nn[i];
    27         else minn=min(minn,sum/nn[i]);
    28     }
    29     cout<<minn<<endl;
    30     return 0;
    31 }
    View Code

    D - Flood Fill

    题意

    给定一个序列,每次可以取一段相同的子序列(连续且值一样),把它的值全部变成任意值。

    问最少多少次操作之后这个序列只剩下一种数。

    分析

    一开始想错题意了,我以为是可以“感染”附近的一个序列,让它变成自己是一样的,忘记了如果两端的颜色一样,只进行一次操作就可以达成了。

    其实是一个很明显的$dp$,优化比较难以想到。

    $f[l][r][0/1]$表示转化区间$l,r$,左/右端的点颜色保持不变。

    那么我们递推就很明显了

    $f[l][r][0]=min{f[l+1][r][0]+(a[l]!=a[l+1]),f[l+1][r][1]+(a[l]!=a[r])}$

    $f[l][r][1]=min{f[l][r-1][1]+(a[r]!=a[r-1]),f[l][r-1][0]+(a[l]!=a[r])}$

    迭代可能不好实现,我们可以用递归,记忆化搜索实现。

    代码

     1 #include <bits/stdc++.h>
     2 #define ll long long 
     3 #define Mid ((l+r)>>1)
     4 #define ull unsigned long long
     5 using namespace std;
     6 const int N=5005;
     7 int read(){
     8     char c;int num,f=1;
     9     while(c=getchar(),!isdigit(c))if(c=='-')f=-1;num=c-'0';
    10     while(c=getchar(), isdigit(c))num=num*10+c-'0';
    11     return f*num;
    12 }
    13 int n,a[N],f[N][N][2];
    14 void memorycheck(){
    15     double x=sizeof n+sizeof a+sizeof f;
    16     cout<<(x/1024/1024)<<"MB"<<endl;
    17 }
    18 int dp(int l,int r,int p){
    19     if(l>=r)return 0;
    20     if(f[l][r][p])return f[l][r][p];
    21     int res=0;
    22     if(!p){
    23         res=dp(l+1,r,0)+(a[l]!=a[l+1]);
    24         res=min(res,dp(l+1,r,1)+(a[l]!=a[r]));
    25     }else {
    26         res=dp(l,r-1,0)+(a[r]!=a[l]);
    27         res=min(res,dp(l,r-1,1)+(a[r]!=a[r-1]));
    28     }
    29     return f[l][r][p]=res;
    30     
    31 }
    32 int main()
    33 {
    34     //memorycheck();
    35     n=read();
    36     for(int i=1;i<=n;i++){
    37         a[i]=read();
    38         if(a[i]==a[i-1])i--,n--;
    39     }
    40     cout<<min(dp(1,n,0),dp(1,n,1))<<endl;
    41     return 0;
    42 }
    43 
    44 [close]
    View Code
  • 相关阅读:
    dedecms5.7百度主动推送(实时) 开发
    胆囊结石食物选择
    读《遥远的救世主》与观看电视剧天道
    cnn健康增胖和调理好身体
    Machine-wide Progress Telerik Fiddler installation has been found at ...Please, use that one or uninstall it ...
    鼻炎治疗之路(转载)
    学医后才知道的小知识...
    一点浩然气,千里快哉风(修炼孟子浩然之气)
    孟尝君的逆袭
    张小龙和张一鸣的对立统一
  • 原文地址:https://www.cnblogs.com/onglublog/p/10370162.html
Copyright © 2011-2022 走看看