空降题目处(外网)
点我点我点我
空降题目处(内网)
点我点我点我
Description
两人取一堆n个石子 先手不能全部取完 之后每人取的个数不能超过另一个人上轮取的数*K。取完最后一个石子的人获胜。给n,K判断先手必胜并求第一步。
Input
第一行为一个正整数t(1<=t<=10),表示共t组测试数据
接下来t行,每行包括两个正整数n,k
Output
共t行,第i行先输出“Case i: ”(不包括引号),接着输出结果,若先手有必胜策略则输出第一次取的石子数(答案不唯一,输出第一步最小选几),否则输出lose。
Solution
题解难懂,讲讲通俗的.
只讲
K≥2
.
构造
A,B
数列,使得
A1∼i
若干个互不相邻的数的和都可等于
B1∼i
的数.
已知
A1∼i
是不可能得出
Bi+1
的,所以
Ai+1=Bi+1
.
∴Bi+1=Bt+Ai+1(At∗K<Ai+1)
求
A
构造出
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.