牛客练习赛117 C&D
C 分类讨论贪心
显然的,正面考虑怎么拼团会很麻烦,所以我们从另一个视角考虑,求出可能的最大团数,然后看一看怎么踢人能够使落单的最少。
当K为偶数的时候,显然最大团数就是\((n+m*2)/k\),而当K为奇数的时候,显然男生抱团需要至少一个男生,女生抱团也需要至少一个男生,最大团数就是\(min(n,(n+m*2)/k)\),然后进一步考虑
显然女生因为价值高,让她落单应该优先。
#include<iostream>
#include<cstdio>
using namespace std;
int t;
long long n,m,k;
int main(){
scanf("%d",&t);
while(t--){
scanf("%lld%lld%lld",&n,&m,&k);
int d=min(n,(n+m*2)/k);
if(k%2==0) d=(n+m*2)/k;
int res=n+m*2-d*k;
if(res<=m*2) printf("%lld\n",res/2+res%2);
else printf("%lld\n",res-m*2+m);
}
return 0;
}
D
如果最后变成了反面朝上,显然的是所有的硬币都被操作了奇数次。
所以当k为奇数的时候,显然可以,只要每个硬币开头搞一次就可以了。
当K为偶数的时候,如果n为奇数,显然任意次操作后反面朝上的硬币为偶数个,不合题意。
如果n也是偶数,那么可以把相邻的硬币看作是一个大硬币,转换成小问题。
#include<cstdio>
#include<iostream>
using namespace std;
int t;
int n,k;
int gcd(int a,int b){
if(b==0) return a;
else return gcd(b,a%b);
}
void deal(){
if(k&1){
printf("%d\n",n);
for(int i=1;i<=n;++i)
printf("%d ",i);
printf("\n");
}else{
if((n&1)){
printf("-1\n");
}else{
int tem=gcd(n,k);
if((k/tem)%2==0){
printf("-1\n");
}else{
printf("%d\n",n/tem);
for(int i=1;i<=n;i+=tem)
printf("%d ",i);
printf("\n");
}
}
}
}
int main(){
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&k);
deal();
}
return 0;
}