September 17th 模拟赛C T3 石子游戏 Solution

空降题目处(外网)
点我点我点我

空降题目处(内网)
点我点我点我

Description

两人取一堆n个石子 先手不能全部取完 之后每人取的个数不能超过另一个人上轮取的数*K。取完最后一个石子的人获胜。给n,K判断先手必胜并求第一步。

Input

第一行为一个正整数t(1<=t<=10),表示共t组测试数据
接下来t行,每行包括两个正整数n,k

Output

共t行,第i行先输出“Case i: ”(不包括引号),接着输出结果,若先手有必胜策略则输出第一次取的石子数(答案不唯一,输出第一步最小选几),否则输出lose。

Solution

题解难懂,讲讲通俗的.
只讲 K2 .
构造 A,B 数列,使得 A1i 若干个互不相邻的数的和都可等于 B1i 的数.
已知 A1i 是不可能得出 Bi+1 的,所以 Ai+1=Bi+1 .
Bi+1=Bt+Ai+1(AtK<Ai+1)
A 构造出N的最小数,即从后往前搜 A ,N能减就减,减完后到前面第2个判断.

Code

C++

#include<fstream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;

int t,n,k,i,j,q=1,a[10000000],b[10000000];

int bs(int l,int r,int x);

int main()
{
    scanf("%d",&t);
    for (int loop=1;loop<=t;loop++)
    {
        scanf("%d%d",&n,&k);
        printf("Case %d: ",loop);
        if (k==1)
        {
            int p=1;
            while ((n&p)==0)
            {
                p*=2;
            }
            if (p==n)
                printf("lose\n");
            else
                printf("%d\n",p);
        }
        if (k>=2)
        {
            a[1]=b[1]=1;
            i=j=0;
            q=k;
            while (a[i]<n)
            {
                i++;
                a[i+1]=b[i]+1;
                while (a[j+1]*k<a[i+1])
                    j++;
                b[i+1]=b[j]+a[i+1];
            }
            if (a[i]==n)
            {
                printf("lose\n");
                continue;
            }
            q=1;
            while (n!=0)
            {
                i--;
                if (a[i]<=n)
                {
                    n-=a[i];
                    i--;
                }
            }
            printf("%d\n",a[i+1]);
        }
    }
}

Pascal

var
        i,j,l,n,m,ii:longint;
        k,x,y:longint;
        a,b:array[0..1001000] of int64;
        //bz:array[0..10100000] of boolean;
begin
        //assign(input,'stone_2.in'); reset(input);
        //assign(output,'stone_2.out'); rewrite(output);
        readln(n);
        for ii:=1 to n do
        begin
                readln(x,y);
                write('Case ',ii,': ');
                a[1]:=1;
                b[1]:=1;
                i:=0;
                j:=0;
                while a[i]<x do
                begin
                        inc(i);
                        a[i+1]:=b[i]+1;
                        //bz[a[i+1]]:=true;
                        while a[j+1]*y<a[i+1] do inc(j);
                        //if j=1 then b[i+1]:=a[i+1] else
                        b[i+1]:=b[j]+a[i+1];
                end;
                if a[i]=x then writeln('lose') else
                begin
                        k:=x;
                        while 1>0 do
                        begin
                                while k<a[i] do dec(i);
                                if k=a[i] then break;
                                k:=k-a[i];
                        end;
                        writeln(k);
                end;
        end;
        //close(input);
        //close(output);
end.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值