POJ 1012 Joseph
Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 53862 | Accepted: 20551 |
Description
Suppose that there are k good guys and k bad guys. In the circle the first k are good guys and the last k bad guys. You have to determine such minimal m that all the bad guys will be executed before the first good guy.
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 }
作 者:Angel_Kitty
出 处:https://www.cnblogs.com/ECJTUACM-873284962/
关于作者:阿里云ACE,目前主要研究方向是Web安全漏洞以及反序列化。如有问题或建议,请多多赐教!
版权声明:本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。
特此声明:所有评论和私信都会在第一时间回复。也欢迎园子的大大们指正错误,共同进步。或者直接私信我
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是作者坚持原创和持续写作的最大动力!
欢迎大家关注我的微信公众号IT老实人(IThonest),如果您觉得文章对您有很大的帮助,您可以考虑赏博主一杯咖啡以资鼓励,您的肯定将是我最大的动力。thx.
我的公众号是IT老实人(IThonest),一个有故事的公众号,欢迎大家来这里讨论,共同进步,不断学习才能不断进步。扫下面的二维码或者收藏下面的二维码关注吧(长按下面的二维码图片、并选择识别图中的二维码),个人QQ和微信的二维码也已给出,扫描下面👇的二维码一起来讨论吧!!!
欢迎大家关注我的Github,一些文章的备份和平常做的一些项目会存放在这里。