急开锁

版权声明:未经过同意不得转载 https://blog.csdn.net/qq_42500298/article/details/82872889

题目描述

沃老师来到某海滨城市上班,晚上乘坐高铁回家,发现钥匙断在锁孔里,无法开门了。于是他拨打了鞋底上不小心踩到的公安局备案急开锁广告上面的电话。不久,开锁师傅来到沃老师家门前。师傅发现沃老师家的门锁很特殊,必须把锁孔内的钥匙全部敲断后才能取出。具体来说,锁孔内的钥匙长度为l, 师傅第一下可以选择敲掉1,2,…或者l−1长度的钥匙。假设师傅选择敲掉长度为x的钥匙。那么钥匙的长度就会减少x。由于力道难以掌握,这之后钥匙的长度还会再减少1到kx之间的一个随机长度y(只会随机出整数)。如果在这个随机减少的过程中,钥匙的长度减少为0(或者减少为负数),那么钥匙就会剩下最后一点卡在锁里面再也无法取出,开锁就失败了。如果没有失败,则师傅可以再次选择一个新的长度x,令钥匙的长度减少x。因为取钥匙时一下长一下短会显得师傅很不专业,x必须是正整数不能超过y的k倍。如果钥匙长度减少x后恰好为0,开锁就成功了。如果还没有减少到0,则开锁过程继续。钥匙会自己再随机减少1到kx之间的长度y,如果钥匙自己减少到0,开锁就失败了。该过程不断往复,每次师傅都要敲掉之前钥匙自己减少的长度的k倍以内的一个正整数长度,之后钥匙就会自己减少师傅敲掉的长度的k倍以内的一个随机正整数长度。如果师傅敲后钥匙长度减少为0,则开锁成功。如果钥匙自己减少到0,开锁失败。现在给定k和l,问师傅能不能保证(即最差情况下)成功开锁。

输入描述:

第一行一个正整数T表示数据组数。(1≤T≤10,10租数据共享4秒时限)每行一组数据,包含两个正整数k和l。(2≤k≤100000,2≤l≤1018)

输出描述:

对于每组数据输出一行,如果能保证成功开锁,输出"GOD",否则输出"DOG"(均不含引号)。

示例1

输入

4
2 20
3 10
100000 1000000000000000000
2 21

输出

GOD
GOD
GOD
DOG

备注:

对于30%的数据,k和l不超过700。对于另外30%的数据,k=2。

思路:

本题题意是有一堆石子,先手可取任意数量的石子但是无法直接全部取走, 此后每个人可取前一个人取走的k倍以内任意数量的石子(不能不取),取 走最后一个石子的赢,问先手是否必胜。
我们首先打表找规律,可以发现k等于2时,先手输当且仅当l为斐波那契数。 可得30分。继续观察可以发现无论k是多少,先手如果在l=n时会输,那么我 们找一个n/k<=m<n的最小的使得先手输的m,先手在l=n+m的时候也只 能输掉。(在n和n+m之间都是获胜的)
找到规律后很好实现,O(klog(l)log(klog(l)))(每次二分查找m)就可以通 过。
归纳证明: 如果l在n和n+m之间,先手将石子数变为n即可。这时后手面对l=n的情况, 且限制更强了(本来能随便拿,现在只能拿先手拿的k倍以内),只能输掉。 如果l是n+m,先手不能直接拿走m个,因为m太大了,后手下一步直接获 胜。现在后手可以先按照玩m个石子的游戏的策略,保证自己拿走m个石子 中的最后一个。先手就会被留下n个石子,只能输掉。

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll gti(void)
{
    char c=getchar();
    ll ret=0,st=1;
    for (;!isdigit(c);c=getchar()) if (c=='-') st=-1;
    for (;isdigit(c);c=getchar()) ret=ret*10+c-'0';
    return ret*st;
}
ll x[7000000];
int main(void)
{
    for (int t=gti();t>0;t--)
    {
        ll k=gti(),l=gti(),tot=0,m=1;
        if (l<=k+1)
        {
            puts("DOG");
            continue;
                    }
        for (int i=1;i<=k+1;i++)
            x[++tot]=i;
        while (x[tot]<l)
        {
            ll n=x[tot],lst=n/k+(n%k?1:0);
            while (x[m]<lst) ++m;
                        x[++tot]=n+x[m];
        }
        puts(x[tot]==l?"DOG":"GOD");
    }
    return 0;
}

来源:nkw

猜你喜欢

转载自blog.csdn.net/qq_42500298/article/details/82872889
今日推荐