HDU 6869 Slime and Stones (威佐夫博弈扩展)

原题题面

Orac and Slime are playing a game.
There are two groups of stones, the first group contains a stones and the second contains b stones. Orac and Slime operate them by turns in the game. For each operation, they have two choices:

  1. Pick up any number of stones from a certain group;
  2. Pick up x x x stones from the first group and y y y from the second group, which x , y x,y x,y satisfy ∣ x − y ∣ ≤ k |x−y|≤k xyk. k k k is a given constant.
    Notice that not picking up any stone in an operation is not allowed. If there is no stone left in both groups at the beginning of one’s turn, he loses the game.
    Orac would like to know whether there exists a winning strategy for him if he operates first. They will play many times, so he will make multiple queries.

输入格式

The first line contains one integer T ( 1 ≤ T ≤ 1 0 5 ) T(1≤T≤10^5) T(1T105), which stands for the number of queries that Orac makes.
In the following T T T lines, each line contains three integer a , b , k ( 1 ≤ a ≤ 1 0 8 , 1 ≤ b ≤ 1 0 8 , 0 ≤ k ≤ 1 0 8 ) a,b,k(1≤a≤10^8,1≤b≤10^8,0≤k≤10^8) a,b,k(1a108,1b108,0k108).

输出格式

The output contains T T T lines, with an integer 0 0 0 or 1 1 1 in each line, stand for there exist/not exist a winning strategy for the given situation.

输入样例

4
1 2 0
2 4 0
1 2 1
2 6 1

输出样例

0
1
1
0

Hint

n the first query, if Orac picks up all the stones from a group, Slime will pick up all the stones from the other group, and if Orac picks up a stone from the second group, Slime will pick up a stone from both groups.

题面分析

易知 k = 0 k=0 k=0时为威佐夫博弈的一般形式。
k = 1 k=1 k=1时,我们可以利用威佐夫博弈的类似推导方法——去寻找必败态。
对于两个石堆 ( a , b ) (a,b) (a,b),不妨设 a ≤ b a\leq b ab,稍加打表可以得到
(1,3)
(2,6)
(4,10)
(5,13)
(7,17)
(8,20)

于是我们可以得到一个规律:
a [ i ] = a [ i ] a[i]=a[i] a[i]=a[i] b [ i ] b[i] b[i]中未出现的最小值, b [ i ] = a [ i ] + i ∗ ( k + 1 ) b[i]=a[i]+i*(k+1) b[i]=a[i]+i(k+1)
我们知道威佐夫博弈的通项是 a [ i ] = [ i ∗ f ] , b [ i ] = a [ i ] + i , ( f = 1 + 5 2 ) a[i]=[i*f],b[i]=a[i]+i,(f=\frac{1+\sqrt{5}}{2}) a[i]=[if],b[i]=a[i]+i,(f=21+5 )
这个和威佐夫博弈的形式很像,所以我们可以用类似的方法推导公式——Betty方程(具体证明过程请自行百度贝蒂定理,这里不再赘述)。
我们列出Betty方程 1 α + 1 α + k + 1 = 1 \frac{1}{\alpha}+\frac{1}{\alpha+k+1}=1 α1+α+k+11=1
解得 α = 1 − k + k 2 + 2 k + 5 2 \alpha=\frac{1-k+\sqrt{k^2+2k+5}}{2} α=21k+k2+2k+5
因此我们可以得到
a [ i ] = ⌊ 1 − k + k 2 + 2 k + 5 2 i ⌋ a[i]=\lfloor\frac{1-k+\sqrt{k^2+2k+5}}{2}i\rfloor a[i]=21k+k2+2k+5 i
b [ i ] = ⌊ 3 + k + k 2 + 2 k + 5 2 i ⌋ b[i]=\lfloor\frac{3+k+\sqrt{k^2+2k+5}}{2}i\rfloor b[i]=23+k+k2+2k+5 i
所以验证的时候只需要先计算 i i i即可。
注意到 b [ i ] − a [ i ] = ⌊ ( k + 1 ) i ⌋ b[i]-a[i]=\lfloor (k+1)i\rfloor b[i]a[i]=(k+1)i
所以 i = ⌊ b [ i ] − a [ i ] k + 1 ⌋ i=\lfloor\frac{b[i]-a[i]}{k+1}\rfloor i=k+1b[i]a[i]
然后验证下 a [ i ] , b [ i ] a[i],b[i] a[i],b[i]的值对不对即可(按理来说只需要验证一个,但 α \alpha α是个浮点数,会有精度误差)

AC代码(78ms)

#include<bits/stdc++.h>
using namespace std;
const int maxn=5e7;
#define _rep(i, a, b) for(int i=(a);i<=(b);i++)
#define _repp(i, a, b) for(int i=(a);i<(b);i++)
#define _per(i, a, b) for(int i=(b);i>=(a);i--)
#define _pper(i, a, b) for(int i=(b);i>(a);i--)
#define mem(a) memset(a,0,sizeof(a))
double f1(double k)
{
    double delta=(sqrt(k*k+2*k+5.0)+1-k*1.0)/2.0;
    return delta;
}
double f2(double k)
{
    double delta=(sqrt(k*k+2*k+5.0)+3+k*1.0)/2.0;
    return delta;
}
inline void solve()
{
    int t;
    scanf("%d", &t);
    while(t--)
    {
        int a,b,k;
        scanf("%d%d%d",&a,&b,&k);
        if(a>b)
            swap(a,b);
        double k1=f1(k*1.0);
        double k2=f2(k*1.0);
        int d=(b-a)/(k+1);
        if(floor(d*k1)==a && floor(d*k2)==b)
        {
            printf("0\n");
        }
        else
        {
            printf("1\n");
        }
    }
}
signed main()
{
//    ios_base::sync_with_stdio(false);
//    cin.tie(0);
//    cout.tie(0);
#ifdef ACM_LOCAL
    freopen("in.txt", "r", stdin);
    freopen("out.txt", "w", stdout);
    long long test_index_for_debug=1;
    char acm_local_for_debug;
    while(cin>>acm_local_for_debug)
    {
        cin.putback(acm_local_for_debug);
        if (test_index_for_debug>100)
        {
            throw runtime_error("Check the stdin!!!");
        }
        auto start_clock_for_debug=clock();
        solve();
        auto end_clock_for_debug=clock();
        cout<<"\nTest "<<test_index_for_debug<<" successful"<<endl;
        cerr<<"Test "<<test_index_for_debug++<<" Run Time: "
            <<double(end_clock_for_debug-start_clock_for_debug)/CLOCKS_PER_SEC<<"s"<<endl;
        cout<<"--------------------------------------------------"<<endl;
    }
#else
    solve();
#endif
    return 0;
}

后记

赛时结束前5分钟推出结论,赛后5分钟迟迟AC…
DrGilbert 2020.8.18

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值