牛客练习赛117 C&D

发布时间 2023-11-04 13:09:36作者: Simex

Link

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;
}