POJ3210-推导

题目:题目链接


题意:Snoopy想问下,若有n枚硬币,这n枚硬币的初始状态是任意的,则至少需要翻转几次,才能保证对于任何一种初始状态而言,都能变成n枚硬币全为正或全为反。
 
思路:若n为偶数:
      1: 若初始状态为偶数正面 + 偶数反面,要想变成全正或全反,翻转的次数必为偶数。
         例如: ○○●●●●  则翻转 2,4,6,8……次均可。
      2: 若初始状态为奇数正面 + 奇数反面,要想变成全正或全反,翻转的次数必为奇数。
         例如: ○○○○○●  则翻转 1,3(先将●翻为○,再将任一个○翻两下),5,7……次均可。
      因次,我们就无法得到一个确定的翻转次数x,让它能使任意初始状态的硬币变成全为正或全为反,因为若x为偶数,则无法满足例2,若x为奇数,则无法满足例1。故应输出"No Solution!"。
      若n为奇数:
      初始状态只可能为偶数正面 + 奇数反面(偶数反面 + 奇数正面同理),故要想变成全正或全反,是必能找出一个次数x满足所有任意情况的。
      1:对初始状态即全为奇数个正面而言,翻转的次数必为偶数。
      2: 由1得只能翻所有正面为反面,因为这样才需翻转偶数次。
         例如: ○○○○●●●  则翻转4,6,8,10……次均可,其中最小为4。要保证对7枚硬币的任意初始状态都可行,则最小应为 7-1=6 ,否则对 ○○○○○○● 无法实现。 
      因此,当你为奇数是,最少翻转次数为n-1。


#include <iostream>
#include <cstdio>
#include <string>
#include <string.h>
#include <map>
#include <vector>
#include <cstdlib>
#include <algorithm>
#include <cmath>
#include <queue>
#include <set>
#include <stack>
#include <functional>
#include <fstream>
#include <sstream>
#include <iomanip>
#include <numeric>
#include <cassert>
#include <bitset>
#include <stack>
#include <ctime>
#include <list>
#define INF 0x7fffffff
#define max3(a,b,c) (max(a,b)>c?max(a,b):c)
#define min3(a,b,c) (min(a,b)<c?min(a,b):c)
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
int gcd(int  n,int  m)
{
    if(n<m) swap(n,m);
    return n%m==0?m:gcd(m,n%m);
}
int  lcm(int  n,int  m)
{
    if(n<m) swap(n,m);
    return n/gcd(n,m)*m;
}
#define N 10000007
int prime[N];
struct node
{
    int x, y;
};
bool cmp(const node & a, const node & b)
{
    return a.x > b.x;
}
void getPrime();
void bash();
void wzf();
void SG();
int QuickMod(int a, int b, int n);
int main()
{
    int n;
    while(scanf("%d", &n))
    {
        if(!n)
        break;
        if(n % 2 == 0)
        printf("No Solution!\n");
        else
        printf("%d\n", n-1);
    }
    return 0;
}

int QuickMod(int  a,int b,int n)
{
    int r = 1;
    while(b)
    {
        if(b&1)
            r = (r*a)%n;
        a = (a*a)%n;
        b >>= 1;
    }
    return r;
}

void getPrime()
{
    memset(prime, 0, sizeof(prime));
    prime[0] = 1;
    prime[1] = 1;
    for(int i = 2; i < N; ++i)
    {
        if(prime[i] == 0)
        {
            for(int j = i+i; j < N; j+=i)
                prime[j] = 1;
        }
    }
}

void bash(int n, int m)
{
    if(n%(m+1) != 0)
        printf("1\n");
    else
        printf("0\n");
}

void wzf(int n, int m)
{
    if(n > m)
        swap(n, m);
    int k = m-n;
    int a = (k * (1.0 + sqrt(5.0))/2.0);
    if(a == n)
        printf("0\n");
    else
        printf("1\n");
}

int numsg[N];
void SG(int n)
{
    int sum = 0;
    for(int i=0; i < n; i++)
    {
        scanf("%d",&numsg[i]);
        sum ^= numsg[i];
    }
    if(sum == 0)
        printf("No\n");
    else
    {
        printf("Yes\n");
        for(int i = 0; i < n; i++)
        {
            int s = sum ^ numsg[i];
            if(s < numsg[i])
                printf("%d %d\n", numsg[i], s);//从有num[i]个石子的堆后剩余s个石子
        }

    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值