您的位置:首页 > 其它

51nod1613翻硬币规律!

2016-03-02 20:21 260 查看
理论解法转自知乎,原文链接:http://www.zhihu.com/question/26570175/answer/33312310

题目链接:http://www.51nod.com/contest/problem.html#!problemId=1613

【有 n 个硬币,一开始全部正面朝上,每次可以翻转 k 个硬币( k 小于 n ),那么至少要 p 次翻转,才能让所有硬币反面朝上,求 p 的值】

高能预警:

本题所用的数学工具不超过初中毕业水平,但情况繁多,完整讨论并不容易,结论写在最后。

解:


本题的精髓在于对奇偶性的讨论。

——情况1:若 n 为奇数——

1.1 若 k 为偶数 => 无解

证明


若要让所有硬币最终翻面,则每个硬币都要翻面奇数次,共有奇数个硬币,所以所有硬币的翻面总数为奇数,但每次只能翻面偶数个硬币,显然不可能。证毕!

1.2 若 k 为奇数 => p为不小于 n/k 的最小奇数

(例1:n=7,k=5,那么 n/k =1.4 则 p=3 )

(例2:n=25,k=7,那么 n/k= 25/7 则 p=5)

证明

必要性

若要让所有硬币最终翻面,则每个硬币都要翻面奇数次,共有奇数个硬币,所以所有硬币的翻面总数为奇数,而每次只能翻奇数个硬币,所以总的翻转次数必然是奇数次,而翻转次数不到 n/k 次时,并不能使所有硬币至少翻面1次,所以p至少是不小于 n/k 的最小奇数

充分性:



时,只要3次翻转即可

给硬币编号为1-n,

第1次翻转编号:1~n-2

第2次翻转编号:1~n-3、n-1

第3次翻转编号:1~n-3、n

Done!(前 n-3 个硬币翻面 3 次,后 3 个翻面 1 次)



时,依然只要3次翻转

只要让前面的

个硬币翻转 3 次,后面的

个硬币翻转
1 次即可。这是显然可以做到的。



时,需要p次翻转(p为不小于 n/k 的最小奇数)

根据定义,

,

,由于

,所以

这意味者翻转
p 次后,平均来说,每个硬币翻面次数小于3次。只要让前面的

个硬币翻转 3 次,后面的

个硬币翻转
1 次即可。

——情况2:若 n 为偶数——

2.1 若

且为偶数=> p=3


只要让前面的

个硬币翻转 3 次,后面的

个硬币翻转
1 次即可。

这个情况,和 n 为奇数是类似的。

2.2 若

且为奇数=>p为不小于 n/(n-k) 的最小偶数


这种情况比较特殊。

首先由奇偶性得出翻转次数必为偶数,而每一枚硬币翻转的次数为奇数,则每一枚硬币至少不翻转 1 次。

其次,每次有 n-k 枚不翻转,所以 p 必须不小于 n/(n-k) 。

方案:让前面

硬币翻转 p-1 次,后面

硬币翻转
p-3 次

2.3 若

且为偶数=> p为不小于 n/k 的最小整数




时,显然 p=2;

反之,只要让前面的

个硬币翻转 3 次,后面的

个硬币翻转
1 次即可。

2.4 若

且为奇数=> p为不小于 n/k 的最小偶数



时,显然 p=2;

反之,首先由奇偶性得出翻转次数必为偶数,

只要让前面的

个硬币翻转 3 次,后面的

个硬币翻转
1 次即可。

————————————

综上所述:

若 n 为奇数:


若 k 为偶数

无解

若 k 为奇数

p 为不小于 n/k 的最小奇数

若 n 为偶数:

若 k为偶数,且


若 k为奇数,且

p 为不小于 n/(n-k) 的最小偶数

若 k为偶数,且



p
为不小于 n/k 的最小整数

若 k为奇数,且



p
为不小于 n/k 的最小偶数

#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <set>
#include <iomanip>

using namespace std;
//#pragma comment(linker, "/STACK:102400000,102400000")
#define maxn 10
#define MOD 1000000007
#define mem(a , b) memset(a , b , sizeof(a))
#define LL long long
#define INF 100000000

int main()
{
long long n , k;
while(cin >> n >> k)
{
if(n % 2)
{
if(k%2 == 0) cout << -1 << endl;
else
{
LL tmp = n/k;
if(n%k) tmp ++;
// cout << tmp << endl;
if(tmp % 2 == 0) tmp ++;
cout << tmp << endl;
}
}
else
{
if(k == n-1) cout << n << endl;
else if(k == n/2) cout << 2 << endl;
else if(k % 2 && k > n/2 && k < n-1) //cout << 4 << endl;
{
int tmp = n / (n-k);
if(n % ( n - k) ) tmp ++;
if(tmp & 1) tmp ++;
cout << tmp << endl;
}
else if(k % 2 == 0&& k > n/2 && k < n-1) cout << 3 << endl;
else if(k %2 && k < n/2)
{
int tmp = (n/k);
if(n%k) tmp ++;
if(tmp%2) tmp++;
cout << tmp << endl;
}
else if(k %2 == 0 && k < n/2)
{
int tmp = ceil(n/k);
if(n%k) tmp ++;
cout << tmp << endl;
}
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: