51nod 1613 翻硬币

题目描述

有 n 个硬币,一开始全部正面朝上,每次可以翻转 k 个硬币( k 小于 n ),那么至少要 p 次翻转,才能让所有硬币反面朝上,求 p 的值。如果不能成功翻转则输出-1
数据范围
n,k (1 <= n <= 10^9, 1 <= k <= 10^9)。

看数据范围就知道,复杂度应该为O(1)

本题的精髓在于对奇偶性的讨论。
情况1:若 n 为奇数——
1.1 若 k 为偶数 => 无解
证明:
若要让所有硬币最终翻面,则每个硬币都要翻面奇数次,共有奇数个硬币,所以所有硬币的翻面总数为奇数,但每次只能翻面偶数个硬币,显然不可能。证毕!
1.2 若 k 为奇数 => p为不小于 n/k 的最小奇数
证明:
若要让所有硬币最终翻面,则每个硬币都要翻面奇数次,共有奇数个硬币,所以所有硬币的翻面总数为奇数,而每次只能翻奇数个硬币,所以总的翻转次数必然是奇数次,而翻转次数不到 n/k 次时,并不能使所有硬币至少翻面1次,所以p至少是不小于 n/k 的最小奇数。而p为奇数,k为奇数,所以总次数为奇数,而且我们保证了所有硬币至少翻了一次,同时可以保证所有硬币的翻转次数为奇数,所以p为不小于 n/k 的最小奇数是能保证有解的,且p就是最小解。
情况2:若 n 为偶数——
2.0若k=n-1,p=n
2.1 若 n/2<k<n1 且为偶数=> p=3
这个情况,和 n 为奇数是类似的。
2.2 若 n/2<k<n1 且为奇数=>p=4
这种情况比较特殊。
首先由奇偶性得出翻转次数必为偶数,而每一枚硬币翻转的次数为奇数,则每一枚硬币至少不翻转 1 次。
其次,每次有 n-k 枚不翻转,所以 p 必须不小于 n/(n-k) 。
2.3 若k<=n/2且为偶数=> p为不小于 n/k 的最小整数,显然
2.4 若k<=n/2且为奇数=> p为不小于 n/k 的最小偶数
首先由奇偶性得出翻转次数必为偶数,同理可得。

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
int main(){
    int n,k,p;
    scanf("%d%d",&n,&k);
    p=n/k;
    if (n%k!=0) p++; 
    if (n%2==1){ 
        if (k%2==0) printf("-1");else{
            if (p%2==0) p++;
            printf("%d\n",p);
        }
    }else{
        int n1=n/2;
        if (k%2==0){
            if (k>n1) printf("3");else printf("%d\n",p);
        }else{
            int p1=n/(n-k);
            if (n%(n-k)!=0) p1++;
            if (k>n1) printf("%d\n",p1);else {
                if (p%2==1) p++;
                printf("%d\n",p);
            }
        } 
    }
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值