题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2211
杀人游戏
Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 3624 Accepted Submission(s): 1182
解法一:插数法(来源:http://www.cnblogs.com/yuyixingkong/p/3254566.html)
1 #include<stdio.h> 2 int main() 3 { 4 __int64 t,n,k,count,luck,s,p,i; 5 scanf("%I64d",&t); 6 while(t--) 7 { 8 scanf("%I64d%I64d",&n,&k); 9 p=k-1;//插入周期eg:k=3,那么p=2;两个一插 10 for(s=k;s<n+1;)//s为标记,来标记luckboy的位置 11 { 12 i=(s-1)/p;//计算s前面插几个 13 luck=s;//luck是记录上一个s的值 14 s=s+i; 15 } 16 printf("%I64d\n",luck); 17 } 18 return 0; 19 }
以样例代码为例(如下图所示),即参数为10,3.S代表最后一个被杀的人,下面表示如果杀到最后一轮,3号是最后一个被杀掉的。那么倒数第二轮他应该在四号位置,并且倒数第二轮应该比倒数第一轮多一个人。依次类推,倒数第三轮他在五号位置,此时有六个人。需要注意的是S后面的人其实是可有可无的,对结果不影响,观察第三行和第二行,可以得到,输入(5,3)和(6,3)都是一样的结果,结果都是S(5)。第四行就可以得到输入(7,3,)(8,3)(9,3)都是得到S(7)。这样通过下面的流程图可以得到任意(x,3)问题的解。那么怎么得到所有的解呢。
我们可以看到,第三行比第二行新插进来1个数,而第四行比第三行多插2个,这规律就是,对于第x个位置的数,前一轮(即上图的下一行)要比现在的位置靠后 (x-1)/(k-1)个,x-1好理解,k-1怎么理解呢,k是每k个人,杀一个,杀完之后,如果要还原回原来个数的人,那么需要每k-1个人插一个。 所以对于现在第x位置的人,x的前一轮的位置就是 x+(x-1)/(k-1)。
关于x的初值,显然x最小应该等于k,一直增加到等于n,结束。以上图为例,n=10,k=3,x才开始为3,一直增长到10结束,结果为10。
n =10,k=3,a=10。其实当k=3时,n=10,是a=10的下限,我们在图中可以看出来当k=3时,n属于10~13,a=10。
同理,随便输一个数 n=10096,k=28,得到 a =9776。
符合k=28,a =9776,这样的n的范围是[9776,10137].
方法二:递归法
int f(int n,int k) { if(n==k) return k; int t=f(n-n/k,k); return t+(t-1)/(k-1); } int main() { int t,n,k; scanf("%d",&t); while(t--) scanf("%d%d",&n,&k),printf("%d\n",f(n,k)); return 0; }
这个比较难理解,需要推导数学公式。
方法三:打表法
#include <stdio.h> #include <string.h> #include <iostream> using namespace std; typedef __int64 LL; LL INF=2147483648; LL save[101][2100]; int main() { LL ans,b,d,mid; for(LL i=3;i<=100;i++) { ans=i; for(LL j=0;j<2000;j++) { b=ans,d=INF; while(b<=d) { mid=(b+d)/2; if(mid-mid/i == ans) break; if(mid-mid/i>ans) d=mid-1; else b=mid+1; } if( (mid-1)-(mid-1)/i==ans ) ans=mid-1; else ans=mid; save[i][j]=ans; } } int T; scanf("%d",&T); int flag,n,k,cnt; while(T--) { scanf("%d%d",&n,&k); for(int i=1;;i++) { if(save[k][i]>n&&save[k][i-1]<=n) { printf("%I64d\n",save[k][i-1]); break; } } } return 0; }
很暴力,性能远不如前面,但是容易想。