原题: http://codeforces.com/gym/101955/problem/K
题意:
给出n个人的环,约瑟夫环背景,求第 m m m个死的位置。
解析:
先看一遍我的这篇约瑟夫环的博客,就知道怎么做了。
https://blog.csdn.net/jk_chen_acmer/article/details/80083118
其实第 m m m个死也可以从那个式子推过来, n + 1 n+1 n+1个人第 m m m个死的位置相当于 n n n个人第 m − 1 m-1 m−1个死的位置转k个下标。即 A ( n , m ) = ( A ( n − 1 , m − 1 ) + k ) % n A(n,m)=(A(n-1,m-1)+k)\%n A(n,m)=(A(n−1,m−1)+k)%n
当m较小的时候直接推就行了。
对于 m = 1 e 18 , k = 1 e 6 m=1e18,k=1e6 m=1e18,k=1e6的数据,显然 A ( n , m ) = ( A ( n − 1 , m − 1 ) + k ) % n A(n,m)=(A(n-1,m-1)+k)\%n A(n,m)=(A(n−1,m−1)+k)%n的这个 % n \%n %n在很多时候没有用处。
A + x k < n + x x ( k − 1 ) < n − A x < n − A ( k − 1 ) A+xk<n+x\\x(k-1)<n-A\\x<\dfrac{n-A}{(k-1)} A+xk<n+xx(k−1)<n−Ax<(k−1)n−A
处理一下就可以了。
代码:
#include<bits/stdc++.h>
using namespace std;
#define LL long long
LL F(LL n,LL m,LL k){
if(m==1)return (k-1)%n;
return (F(n-1,m-1,k)+k)%n;
}
int main(){
int t,cas=0;scanf("%d",&t);
while(t--){
printf("Case #%d: ",++cas);
LL n,m,k;scanf("%lld%lld%lld",&n,&m,&k);
if(k==1){
printf("%lld\n",m);
continue;
}
if(m<=1e6)printf("%lld\n",F(n,m,k)+1);
else{
LL ct=n-m+1;
LL val=(k-1)%(ct);
LL now=1;
while(now<m){
if(val+k>=ct+1){
ct++;
val=(val+k)%ct;
now++;
continue;
}
LL x=(ct-val-1)/(k-1);
x=min(x,m-now);
now+=x;
val+=k*x;
ct+=x;
}
printf("%lld\n",val+1);
}
}
}