我是靠谱客的博主 默默项链,最近开发中收集的这篇文章主要介绍Codeforces 101864A 打表,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

传送门:题目

题意:

大概意思就是总共有N个犯人,形成一个序列[1-n],有一个犯人在第X位,然后警察们制定了一个规则,让[1-L?]犯人出队,围成一个约瑟夫环,警察们要杀N-1个人,只允许L人中存活一人,杀人规则是:
[1-L?]个犯人围城一个圈,然后留一人,杀一人。比如,下图:
l==8时,[1-8]围成一个圈

留下一号选手,击杀二号选手。
留下三号选手,击杀四号选手。
留下五号选手,击杀六号选手。
留下七号选手,击杀八号选手。
留下一号选手,击杀三号选手。
留下五号选手,击杀七号选手。
留下一号选手,击杀五号选手。
留下一号选手,咦?好像没人可以杀了。我们数一数,上面正好七行,正好满足题意,留下一个幸存者,恭喜一号选手获胜。

不难发现,这正是著名的约瑟夫环问题。而这正好是一个特殊的约瑟夫环:Josephus(n,2)。为什么Josephus(n,2)特殊,稍后再讲。我们继续说题意。

上面L打了个问号,因为题目的意思是,上面区间的右界是[L,N]的任何一个数。也就是说:

第一种情况:[1-L]出队,只允许存活一人
第二种情况:[1-L+1]出队,只允许存活一人
等等
第N-L+1种情况:[1-N]出队,只允许存活一人

没出队的肯定活着
好了,题目问:所有出队的情况,X号犯人,能存活的概率。
其中: 1X,L,N1015 1 ≤ X , L , N ≤ 10 15

题解:

所有出队的情况,N-L+1做分母
分子我们考虑两种情况,一种是X号犯人根本没出队,肯定存活。另一种就是本问题的核心了。如果没有那个神奇的 1015 10 15 ,我们直接写个Josephus(i,2)函数,返回幸存者编号,如果是X,分子++。显然,这道题没有这么简单。完全没有思路,先打个表再说:我们输出:i [1,100],Josephus(i,2)的返回值。

打表代码:
#include <iostream>
using namespace std;
int main(void){
int m=2, ans;
for(int i=1;i<=100;i++){
ans=0;
for(int j=2;j<=i;j++)
ans=(ans+m)%j;//约瑟夫出圈公式
cout<<ans+1<<" ";
}
cout<<endl;
return 0;
}

得到下图结果:
运行结果
看着比较乱,我们不妨换一下行:

1
1 3
1 3 5 7
1 3 5 7 9 11 13 15
1 3 5 7 9 11 13 15 17 19 21 23 25 27 29 31
……

我们发现,每当Josephus(i,2)中,i为 2k,k[0,1,2,3,......] 2 k , k ∈ [ 0 , 1 , 2 , 3 , . . . . . . ] 时,Josephus(i,2)==1,然后开始奇数递增。
一个很神奇的事情发生了,比如说现在X==5,那么X在每一行只能存活1次,所以我们只需要计算[X,N]横跨了那几行,如果是完全横跨,分子++,如果一行中只有部分在[X,N]内,判断一下X值,是不是在区间内就行了,一个很巧妙的办法,直接把X/2,为何巧妙?

AC代码:

#include <iostream>
#include <algorithm>
using namespace std;
#define int long long//作者比较懒,直接把所有int换成long long
void solve(int i)
{
int X, L, N;
scanf("%I64d%I64d%I64d", &X, &L, &N);
int ans = max(X - L, 0ll);
if (X & 1ll) //x是奇数
for (int Y = 1 ; Y + X / 2 <= N ; Y <<= 1)
{//X是1,3,5,7
if (Y + X / 2 < L || Y <= X / 2)//那么X/2就是0,1,2,3,直接就是X的在行的第几位了。
continue;
++ans;
}
int P = ans, Q = N - L + 1;
int g = __gcd(P, Q);//不要忘记化简分子和分母啊,__gcd是algorithm中的一个函数,很方便
P /= g;
Q /= g;
cout << "Case " << i << ": " << P << "/" << Q << "n";
}
signed main()
{//不能是long long main啊,所以我们就用signed吧,反正signed==int
int T;
scanf("%I64d", &T);
for (int i = 1 ; i <= T ; ++i)
solve(i);
}

最后

以上就是默默项链为你收集整理的Codeforces 101864A 打表的全部内容,希望文章能够帮你解决Codeforces 101864A 打表所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(33)

评论列表共有 0 条评论

立即
投稿
返回
顶部