| Time Limit: 1000MS | Memory Limit: 10000K | |
| Total Submissions: 53862 | Accepted: 20551 |
Description
Input
Output
Sample Input
3 4 0
Sample Output
5 30
Source
题意:同样的约瑟夫问题,只是现在有K个好人,K个坏人,确定一个步长,是的在第一个好人被清除之前所有坏人都被清除干净。
题解:
1.坏人被清除掉的先后顺序无关紧要,知道下一个除掉的是好人还是坏人就行了。 2.由于好人一直都是k个,每除掉一个坏人,坏人数-1,所以队列的总数每次-1但是好人一直是前k个 3.下一个被清除的人在队列中的“相对”序号为 s = (s+m-1)%(n-i);
4.只要s>=k,那么下一个被除掉的就是坏人
5.接下来说说m的取值范围:我们考察一下只剩下k+1个人时候情况,即坏人还有一个未被处决,那么在这一轮中结束位置必定在最后一个坏人,那么开始位置在哪呢?这就需要找K+2个人的结束位置,然而K+2个人的结束位置必定是第K+2个人或者第K+1个人,这样就出现两种顺序情况:GGGG.....GGGXB 或 GGGG......GGGBX (X表示有K+2个人的那一轮退出的人)所以有K+1个人的那一轮的开始位置有两种可能即第一个位置或K+1的那个位置,限定m有两种可能:t(k+1) 或 t(k+1)+1; t>=1; 若遍历每一个m必定超时,避免超时则需要打表和限制m的范围。
下面给出AC代码:
1 #include <cstdio>
2 //#include <bits/stdc++.h>
3 using namespace std;
4 int a[14];
5 int f(int k,int m)
6 {
7 int n,i,s;
8 n=2*k;
9 s=0;
10 for(i=0;i<k;i++)
11 {
12 s=(s+m-1)%(n-i);
13 if(s<k) return 0;
14 }
15 return 1;
16 }
17 int main()
18 {
19 int i,k,n;
20 for(k=1;k<=14;k++)
21 {
22 i=k+1;
23 while(1)
24 {
25 if(f(k,i))
26 {
27 a[k]=i;
28 break;
29 }
30 else if(f(k,i+1))
31 {
32 a[k]=i+1;
33 break;
34 }
35 i+=k+1;
36 }
37 }
38 while(scanf("%d",&n)&&n)
39 printf("%d\n",a[n]);
40 return 0;
41 }
原文:http://www.cnblogs.com/yechanglv/p/6941921.html