51nod1073(约瑟夫环)

题目链接: http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1073

 

题意: 中文题诶~


思路: 直接模拟的话O(n*k)的时间复杂度,按照套路来的话这样的题一般是能找规律的;
我们先将n个人的编号改成0~n-1(别问为什么,套路而已),那么第1次报到号码为k-1的人出列,圈里还剩下n-1个人
我们对比一下出列前后的编号:

出列前: 0, 1, 2, 3, 4, 5, 6, ...k-2, k-1, k... n-1
出列后: n-k+1,..................n-2, , 1... n-k

我们可以发现留下的人编号和留下来之前是一一对应的,那么要是能找到对应关系的话问题就迎刃而解了,不过现在数据太多了不好找
(偶就是这里找错了规律然后只过了样例),我们接着往下想想...
按照前面的规律,第n次报数时只有一个人,我们给他重新编号为0.前面我们也知道了某一轮某个人的编号和上一轮是对应的,最后留下的人此时的编号为0,
那么只要我们由它上溯并找到它在第一轮时的编号答案就出来了啦~
我们用f(x)表示最后留下来那个人在第n-x+1轮中的编号(这样做我们就是由f(1)推f(n),更直观一些,反之由f(n)推f(1)也是可以的),那么f(n)+1就是
最终答案了啦.很显然有f(1)=0(因为此时只剩下一个人了嘛),接下来我们需要找到两轮编号之间的映射关系,这个可以有枚举k和x得到,这里就不写枚举
过程了啦~
最后我们可以得到公式 f(x)=(f(x-1)+k)%x;

代码 :
 1 #include 
 2 using namespace std;
 3 
 4 int main(void){
 5     int gg, n, k;
 6     cin >> n >> k;
 7     gg=0;
 8     for(int i=2; i<=n; i++){
 9         gg=(gg+k)%i; //前面说的f(x)只是为了我们更直观地理解,其实直接用一个变量保存上一轮序号就可以了
10     }
11     cout << gg+1 << endl;
12     return 0;
13 }

 

 
    

转载于:https://www.cnblogs.com/geloutingyu/p/6202200.html

你可能感兴趣的:(51nod1073(约瑟夫环))