Codeforces Round #734 (Div. 3)
A. Polycarp and Coins
题目大意:
有一个人买东西付钱,但他只有一元的钱和二元的钱, 现在他要付 n 元, 他使用一元钱的数量和二元钱数量的差值要最小, 问他付 n元使用了多少一元钱和二元钱?
解题思路:
直接将ans=n/3,便可分三种情况输出:
如果n%3==0,则说明刚好能用相同数量的一元钱和两元钱组成,直接输入两个ans即可。
如果n%3==1,说明还需要出一块钱,则输出ans+1和ans即可。
如果n%3==2,则还需多出两块前,但是为了一元钱和两元钱的差值更小,便选择出一张两元钱,则输出ans和ans+1即可。
参考代码:
#include<bits/stdc++.h>
using namespace std;
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int n;
scanf("%d",&n);
int ans=n/3;
if(n%3==0)printf("%d %d\n",ans,ans);
else if(n%3==1)printf("%d %d\n",ans+1,ans);
else printf("%d %d\n",ans,ans+1);
}
// system("pause");
return 0;
}
B1. Wonderful Coloring - 1
题目大意:
求满足以下染色条件的每种染料的染色次数为多少
1.字符要么染成红色或者绿色,要么不染色。
2.相同的颜色之间字符应该互不相同。
3.红色和绿色染色的数量相同。
解题思路:
统计字符的出现次数,对于出现次数大于等于2的便可用每种颜色分一个,对答案的贡献便为1。对于出现次数为一次的便可以进行红一个、绿一个的选择(出现次数为1的数量除2向下取整便是对答案的贡献)。
参考代码:
#include<bits/stdc++.h>
using namespace std;
int t;
char a[100];
int main()
{
scanf("%d",&t);
while(t--)
{
unordered_map<char,int>mm;
scanf("%s",a);
for(int i=0;i<strlen(a);i++)
mm[a[i]]++;
int sum=0,sum2=0;
for(auto it:mm)
if(it.second>=2)sum+=1;
else sum2++;
sum+=sum2/2;
printf("%d\n",sum);
}
// system("pause");
return 0;
}
B2. Wonderful Coloring - 2
题目大意:
求一种染色方案使得满足以下条件(用0-k表示染色的种类,0代表不进行染色):
1.数字染成1-k中颜色中的一种,或者不进行染色。
2.相同颜色的两个数字互不相同。
3.不同颜色的染色数相同。
解题思路:
对数字进行排序处理,便于统计相同数字染色相同的情况。在排序后可用,可用一个b数组来记录每一种颜色染色前的前一个染色数组,每一次染色完后进行更新来避免出现相同数字染色相同的情况。遍历数组,判断每个数字是否能染色,如果不能则continue,最后通过枚举的染色情况处理染色数量不同的情况。(多说无益,思路很难解释清楚,还得看代码)。
参考代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+10;
int n,k;
int b[maxn];
int ans[maxn];
struct node{
int id;
int val;
int x;
}a[maxn];
bool cmp(node x,node y)
{
return x.x<y.x;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
memset(b,0,sizeof(b));
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i].x);
a[i].id=i;
a[i].val=0;
}
sort(a+1,a+1+n,cmp);
int f=1;
for(int i=1;i<=n;i++)
{
if(b[f]!=a[i].x)
{
a[i].val=f;
b[f]=a[i].x;
f++;
if(f>k)f=1;
}
//ans[a[i].id]=a[i].val;
}
if(f!=1)
{
int x=0;
for(int i=n;i>=1;i--)
{
if(a[i].val!=0)
{
a[i].val=0;
x++;
}
if(x==f-1)break;
}
}
for(int i=1;i<=n;i++)
ans[a[i].id]=a[i].val;
for(int i=1;i<=n;i++)
printf("%d ",ans[i]);
printf("\n");
}
//system("pause");
return 0;
}
C. Interesting Story
题目大意:
从n个只包含a、b、c、d、e五种字符的单词中选择若干个,使得满足一种单词的数量大于另外四种单词的数量和,求最大的选单词数。
解题思路:
可以枚举a、b、c、d、e分别最为最大的情况,最后取最大值即可。在枚举过程中可采用贪心思想,对每一种枚举情况进行排序,降低枚举时的复杂度。当枚举a时,我们可以对字符串进行suma-sumb-sumc-sumd-sume这个值从大到小排序,循环遍历字符串时,只要出现了a的个数小于等于其他字符个数的情况就可break。其余情况也是这样。
参考代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+10;
char s[400010];
int n,flag;
struct node{
int suma,sumb,sumc,sume,sumd;
}a[maxn];
bool cmp(node x,node y)
{
if(flag==1)return x.suma-(x.sumb+x.sumc+x.sumd+x.sume)>y.suma-(y.sumb+y.sumc+y.sumd+y.sume);
if(flag==2)return x.sumb-(x.suma+x.sumc+x.sumd+x.sume)>y.sumb-(y.suma+y.sumc+y.sumd+y.sume);
if(flag==3)return x.sumc-(x.sumb+x.suma+x.sumd+x.sume)>y.sumc-(y.sumb+y.suma+y.sumd+y.sume);
if(flag==4)return x.sumd-(x.sumb+x.suma+x.sumc+x.sume)>y.sumd-(y.sumb+y.suma+y.sumc+y.sume);
if(flag==5)return x.sume-(x.sumb+x.suma+x.sumc+x.sumd)>y.sume-(y.sumb+y.suma+y.sumc+y.sumd);
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int maxx=0;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
a[i].suma=0,a[i].sumb=0,a[i].sumc=0,a[i].sumd=0,a[i].sume=0;
scanf("%s",s);
for(int j=0;j<strlen(s);j++)
{
if(s[j]=='a')a[i].suma++;
else if(s[j]=='b')a[i].sumb++;
else if(s[j]=='c')a[i].sumc++;
else if(s[j]=='d')a[i].sumd++;
else a[i].sume++;
}
}
for(int i=1;i<=5;i++)
{
flag=i;
sort(a+1,a+1+n,cmp);
/*for(int j=1;j<=n;j++)
cout<<a[j].suma<<" "<<a[j].sumb<<" "<<a[j].sumc<<endl;
cout<<endl;*/
int sum=0,sum1=0;
for(int j=1;j<=n;j++)
{
if(i==1)
{
sum+=a[j].suma;
sum1+=a[j].sumb+a[j].sumc+a[j].sumd+a[j].sume;
}
else if(i==2)
{
sum+=a[j].sumb;
sum1+=a[j].suma+a[j].sumc+a[j].sumd+a[j].sume;
}
else if(i==3)
{
sum+=a[j].sumc;
sum1+=a[j].sumb+a[j].suma+a[j].sumd+a[j].sume;
}
else if(i==4)
{
sum+=a[j].sumd;
sum1+=a[j].sumb+a[j].sumc+a[j].suma+a[j].sume;
}
else
{
sum+=a[j].sume;
sum1+=a[j].sumb+a[j].sumc+a[j].suma+a[j].sumd;
}
//cout<<sum<<" "<<sum1<<endl;
if(sum<=sum1)
{
maxx=max(maxx,j-1);
break;
}
else if(j==n)maxx=max(maxx,n);
}
//cout<<endl;
}
printf("%d\n",maxx);
}
// system("pause");
return 0;
}
D1. Domino (easy version)
题目大意:
在一个n
×
\times
×m的网格上,可以放置 1
×
\times
× 2 或者 2
×
\times
× 1的多米若骨牌,问在n
×
\times
×m为偶数的情况下能否放置恰好k个1
×
\times
× 2的多米若骨牌。
解题思路:
对于n和m全为偶数的情况下,只能放偶数个1 × \times × 2或者2 × \times × 1的多米若骨牌,所有在这种情况下k一定要为一个偶数。
对于n和m全为奇数的情况下,不管k为奇数或者偶数,全是不可能的情况。
对于n为奇数的情况,可以先放m/2个使得变为n和m全为偶数的情况进行判断。
对于m为奇数的情况,可以发现k为偶数可以满足情况,但是如果k>m/2*n的情况需要特判,因为这种情况是不可能满足的。
参考代码:
#include<bits/stdc++.h>
using namespace std;
int n,m,k;
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d%d%d",&n,&m,&k);
if(n%2==0&&m%2==0)
{
if(k%2==0)printf("YES\n");
else printf("NO\n");
}
else
{
if(n%2==1&&m%2==1)printf("NO\n");
else if(n%2==1)
{
if(n==1)
{
if(k==m/2)printf("YES\n");
else printf("NO\n");
}
else
{
int x=m/2;
if(k-x<0)printf("NO\n");
else if((k-x)%2==0)printf("YES\n");
else printf("NO\n");
}
}
else
{
if(m==1)
{
if(k==0)printf("YES\n");
else printf("NO\n");
}
else
{
if(k>m/2*n)printf("NO\n");
else
{
if(k%2==0)printf("YES\n");
else printf("NO\n");
}
}
}
}
}
// system("pause");
return 0;
}