Gym 101864 A Criminal (约瑟夫环)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/yz467796454/article/details/82952944

题目链接:Gym - 101864 A Criminal

题意:t个样例,m个人围成一圈,m的范围在l到n,一二报数,报数到二的人离开,直至剩下一个人,现在求编号为x的人留下的概率

思路:约瑟夫环有递推公式,f[1] = 0;当一个人的时候,出队人员编号为0,这里编号从0开始,题目是从1开始,f[n] = (f[n-1] + m)%n ,m表示每次数到该数的人出列,n表示当前序列的总人数,一开始按照这个规律写,代码很麻烦,一直没有对,后来知道了当m为2的时候,有结论。当人数sum=2^k+t的时候,留下来的人的编号为2t+1(编号从1开始),所以这一题中,t=(x-1)/2,那么只需要知道几个k使得人数sum符合【l,n】,就是答案,要注意的是,当编号为偶数的时候是不可能被留下的,以及当编号小于人数的时候,默认被留下,特判即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

ll gcd(ll x,ll y){
    return y?gcd(y,x%y):x;
}
int main(){
    int t;
    scanf("%d",&t);
    int c=1;
    while(t--){
        ll x,l,n,len;
        ll ans=0;
        scanf("%lld%lld%lld",&x,&l,&n);
        printf("Case %d: ",c++);
        len=n-l+1;
        if(x>l){
            ans+=x-l;
            l=x;
        }
        if(x%2==0){//偶数情况先特判掉
            if(ans==0)printf("0/1\n");
            else{
                printf("%lld/%lld\n",ans/gcd(ans,len),len/gcd(ans,len));
            }
            continue;
        }
        ll a=(x-1)/2;
        ll sum=1;
        for(int i=0;i<55;i++){
            if(sum+a>=l&&sum+a<=n)ans++;
            sum=sum*2;
        }
        printf("%lld/%lld\n",ans/gcd(ans,len),len/gcd(ans,len));
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/yz467796454/article/details/82952944