反约瑟夫问题 【数论】
本人水平有限,题解不到为处,请多多谅解
本蒟蒻谢谢大家观看
题目:
6162: 反约瑟夫问题
Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 169 Solved: 74
[Submit][Status][Web Board]
Description
著名的约瑟夫问题是这样描述的:N个人排成一个圆圈,然后把这N个人按逆时针方向编号为1、2、…、N;随机产
生一个正整数M,然后从编号为1的人开始按逆时针计数,当某人计数为M的倍数时,该人出队;如此循环下去,直
到队列里只有一个人留下。你现在的任务是:对于输入文件的N和K,其中N为初始时约瑟夫圆圈中的人数,K为约瑟
夫问题中最后留下的人的编号;请你确定一个最小能发生这种结果的正整数M。
生一个正整数M,然后从编号为1的人开始按逆时针计数,当某人计数为M的倍数时,该人出队;如此循环下去,直
到队列里只有一个人留下。你现在的任务是:对于输入文件的N和K,其中N为初始时约瑟夫圆圈中的人数,K为约瑟
夫问题中最后留下的人的编号;请你确定一个最小能发生这种结果的正整数M。
Input
为N和K,0<N≤1000
Output
为最小的正整数M。
Sample Input
10 5
Sample Output
2
HINT
根据上一篇递推公式,我们可以反推M
f[1] = 0; //当一个人的时候,出队人员编号为0
f[n] = (f[n-1] + m)%n //m表示每次数到该数的人出列,n表示当前序列的总人数
则f[j]=(f[j-1]+i)%j //i表示每次数到该数的人出列,j表示当前序列的总人数
当f[n]+1==K时(因为下标从0开始),我们就直接输出i即可
code:
1 #include<bits/stdc++.h> 2 #pragma GCC optimize(3) 3 const int N=1e3+10; 4 using namespace std; 5 int n,m; 6 int f[N]; 7 void inint(){ 8 freopen("josephus.in","r",stdin); 9 freopen("josephus.out","w",stdout); 10 } 11 inline int read(){ 12 int x=0,f=1;char ch=getchar(); 13 while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();} 14 while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} 15 return x*f; 16 } 17 inline void write(int x) 18 { 19 if(x<0)x=-x,putchar('-'); 20 if(x>9)write(x/10); 21 putchar(x%10+'0'); 22 } 23 int main() 24 { 25 //inint(); 26 n=read(),m=read(); 27 for(int i=1;i;i++){ 28 for(int j=1;j<=n;j++){ 29 f[j]=(f[j-1]+i)%j; 30 } 31 if(f[n]+1==m){ 32 printf("%d\n",i); 33 break; 34 } 35 } 36 return 0; 37 }
因为我们要找一个最小的M,所以当满足上述条件是直接berak即可