Gym - 101864A A Criminal (约瑟夫环 M = 2, + 暴力)

A Criminal

After committing a serious crime ( Killing an innocent mosquito who never bites any animal) you are arrested by ACM’s Defense Team. You are the X​-th​ (1 based index​ ) criminal in the ordered list ​of N​ ​criminals. Defense Team are willing to punish criminals for their horrible crime. First day Defense Team take f​irst Y people ​from criminal list and arrange them in a circle ( Just like the picture bellow remember that given picture is valid when Y​ is equal to 8 )

After forming circle they start from criminal one and simulate clockwise​. They skip one person and punish next person from the active list (active list: person who have not been punished yet). When only one person is left in the active list they just do not punish him as he is a special person. The order of punishment when Y​ = 8 is [2, 4, 6, 8, 3 , 7, 5] 1 will not be punished in that case.

 

You know that Defense Team will not take less than L​ from criminal list while making circle and you also know that taking any( in range [L,N]​ ) number of criminal form list is equally probable.

 

You are good at programming so you want to calculate the probability that you will not punished on the first day.

INPUT Specification

First line of the input will contain an integer T​ denoting number of test cases. Next T lines will contain Three Integer X , L , N​.

X​: Your position on Criminal List .

L​: Minimum number of criminal that Defense Team Can take.

N​: Total number of criminal on that list.

 

Constraints

1 ≤ T ≤ 10500

1 ≤ X ≤ N ≤ 10^15

1 ≤ L ≤ N

 

Output Specification

 

For every case print case number (See sample output for exact format) and print the answer ( Probability that you will not punished on first day) as p/q​ format where p​ and are coprime If the answer is 0​, then you should print 0/1​.

 

Sample Input

3

1 1 1

2 3 10

4 1 7

Sample Output

Case 1: 1/1

Case 2: 0/1

Case 3: 3/7

 

Explanation

First Case

There is only one option which is taking one person from list. and you will not be punished because remaining person in circle is 1 already(which is actually you). So ans is 1/1.

Second Case

There are 8 equally probable option for Y (3,4,5,6,7,8,9,10). And for each one of those you are going to be punished. So ans is 0/1

Third Case:

This are 7 equally probable options of Y (1,2,3,4,5,6,7). When Y is 1 or 2 or 3 you will not be punished (Actually you are not even selected to be a part of the circle because your id is 4). So ans is 3/7.

 

题意:题意是给你 三个整数 X ,L ,N.  X 表示当前人的 编号, L 表示每一个 惩罚选取的最少人数, N 是总人数。惩罚人数只选取一次,也就是选取 L ~ N中的一个数, 其中每个数被选取的概率都相同。  对于每一次惩罚,相当于约瑟夫环 M = 2 的情况。  求 X 这个人不被惩罚的概率。

思路:很显然,偶数的情况比较简单,所以我是先将偶数的情况特殊处理,然后在来确定奇数。

对于约瑟夫环 M = 2 的情况,有结论  若选取的总人数是 2^k + t, 则最后留下的人的编号是  2*t + 1。

这样,就可以通过 2 * t + 1 这个式子,算出来 X 这个人为最后幸存者 时的 t,  接着枚举  k ,即枚举 2 的次方,算出所有可能的  留下的是 X 时 的总人数。    然后判断 有多少个数 在 max(L,X)~ N 的范围内,就可以算出 X 这个人存活的概率了。 因为是枚举次方, 所以并不会太多, 66次足够了(枚举小了会 WA)。

 

AC代码:

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

typedef long long ll;
ll pow_t[70];

ll gcd(ll a,ll b){
    ll r = a % b;
    while(r){
        a = b; b = r; r = a % b;
    }
    return b;
}

int main()
{
    pow_t[0] = 1;
    for(int i = 1;i <= 66;i ++)
        pow_t[i] = pow_t[i-1] * 2;
    ll x,l,n;
    int cas = 1;
    int t; scanf("%d",&t);
    while(t --){
        scanf("%I64d%I64d%I64d",&x,&l,&n);
        printf("Case %d: ",cas ++);
        if(n == 1){ printf("1/1\n"); continue; }
        if(x % 2 == 0 && x <= l){ printf("0/1\n"); continue; }              ///必死
        if(x % 2 == 0){ ll g = gcd(x - l,n - l + 1); printf("%I64d/%I64d\n",(x - l) / g,(n - l + 1) / g); continue; }        ///被取必死
        ll t = (x - 1) / 2;
        ll num[70] = {0}, pn = 0;
        for(int i = 0;i <= 66;i ++)       ///枚举
            num[pn ++] = pow_t[i] + t;

        int cnt = 0;
        for(int i = 0;i < pn;i ++){
            if(max(l,x) <= num[i] && num[i] <= n)    ///用 max  是判断 X 与 L 的大小关系
                cnt ++;
        }
        ll f = cnt;
        if(l <= x) f += x - l;
        ll g = gcd(f,n - l + 1);
        printf("%I64d/%I64d\n",f / g,(n - l + 1) / g);
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值