[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
原文地址:https://www.cnblogs.com/onglublog/p/10370162.html