Gym 101864 A Criminal (約瑟夫環)
阿新 • • 發佈:2018-12-13
題意: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; }