hdu 2580 a simple stone game

g ( i ) g(i) g(i)表示 [ 1 , i ] [1,i] [1,i]能够组成的最大的数;
f ( i ) f(i) f(i)表示第 i i i个数的值。

那么有:
f ( i ) = g ( i − 1 ) + 1 , g ( i ) = f ( i + 1 ) − 1 g ( i ) = f ( i ) + g ( a ) ∣ a = M A X { k f ( a ) &lt; f ( i ) } f(i)=g(i-1)+1,g(i)=f(i+1)-1\\ g(i)=f(i)+g(a)|a=MAX\{kf(a)&lt;f(i)\} f(i)=g(i1)+1,g(i)=f(i+1)1g(i)=f(i)+g(a)a=MAX{kf(a)<f(i)}
我们将所有函数都化为 f f f
f ( i ) = f ( i − 1 ) + g ( a ) + 1 ∣ a = M A X { k f ( a ) &lt; f ( i − 1 ) } = f ( i − 1 ) + f ( a + 1 ) ∣ a = M A X { k f ( a ) &lt; f ( i − 1 ) } = f ( i − 1 ) + f ( a ) ∣ a = M I N { k f ( a ) ≥ f ( i − 1 ) } f(i)=f(i-1)+g(a)+1|a=MAX\{kf(a)&lt;f(i-1)\}\\ =f(i-1)+f(a+1)|a=MAX\{kf(a)&lt;f(i-1)\}\\ =f(i-1)+f(a)|a=MIN\{kf(a)\ge f(i-1)\} f(i)=f(i1)+g(a)+1a=MAX{kf(a)<f(i1)}=f(i1)+f(a+1)a=MAX{kf(a)<f(i1)}=f(i1)+f(a)a=MIN{kf(a)f(i1)}
我们再计算一下数列长度:
f ( i ) f ( i − 1 ) = 1 + f ( a ) f ( i − 1 ) ≥ 1 + 1 k \frac {f(i)} {f(i-1)}=1+\frac {f(a)} {f(i-1)}\\ \ge1+\frac 1 k f(i1)f(i)=1+f(i1)f(a)1+k1
即为了表示 [ 1 , n ] [1,n] [1,n]的所有数,产生的序列长度是 O ( l o g 1 + 1 k n ) O(log_{1+\frac 1 k}n) O(log1+k1n)的。

容易用归纳证明任何 n = f ( i ) n=f(i) n=f(i)的情况都是 P P P点:
n = 2 , i = 2 n=2,i=2 n=2,i=2显然成立;
其余情况由 f ( i ) = f ( i − 1 ) + f ( a ) , k f ( a ) ≥ f ( i − 1 ) f(i)=f(i-1)+f(a),kf(a)\ge f(i-1) f(i)=f(i1)+f(a),kf(a)f(i1)可知先手不能一次取完 f ( a ) f(a) f(a)。同时后手必然取得 f ( a ) f(a) f(a)的最后一个石子,这使得先手再次进入 n = f ( i − 1 ) n=f(i-1) n=f(i1)的局面,注意此时先手会受到上一次取的数量的限制,但由于其对于 N P NP NP性存在单调性同时最好情况为 P P P点,所以先手依然处于 P P P点。唯一的例外是 f ( a ) = 1 f(a)=1 f(a)=1的情况,容易分析此时 N P NP NP性并没有变化。所以 n = f ( i ) ∣ i &gt; 2 n=f(i)|i&gt;2 n=f(i)i>2的情况得证。

有了以上结论,容易证明 n ≠ f ( i ) n\neq f(i) n̸=f(i)的情况都是 N N N点:
只需要将 n n n分解,设 n = ∑ i = 1 a i n=\sum_{i=1} a_i n=i=1ai a a a按升序排列。
先手先一次取完 a 1 a_1 a1,因为分解中任意一对数的比都大于 k k k,所以后手不得不面对 n = a 2 n=a_2 n=a2 P P P点,由之前的证明,可知后手必然拿到 a 2 a_2 a2的最后一个石子,这使得先手继续进入 n = a 3 n=a_3 n=a3 P P P点,以此类推。需注意此时先手第一次能够拿的最小值就是 a 1 a_1 a1,否则将会使自己变成 n = a 1 n=a_1 n=a1 P P P点的先手而输掉游戏。

所以我们可以在 O ( l o g 1 + 1 k n ) O(log_{1+\frac 1 k}n) O(log1+k1n)下完成一次计算。

#include<iostream>
using namespace std;
typedef long long ll;
int ar[2000010],n,k,ct=0;
void cl(){
    int i,a;for(scanf("%d %d",&n,&k),ar[1]=1,i=2,a=1;ar[i-1]+1<n;++i){
        for(;(ll)ar[a]*k<ar[i-1];++a);
        ar[i]=ar[a]+ar[i-1];
    }
    printf("Case %d: ",++ct);
    if(ar[i-1]==n)printf("lose\n");
    else{
        for(--i;;--i){
            if(n>=ar[i])n-=ar[i];
            if(!n){printf("%d\n",ar[i]);break;}
        }
    }
};
int main(){
    int t;scanf("%d",&t);
    while(t--)cl();
    return 0;
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值