1. 程式人生 > >POJ - 3517 And Then There Was One (約瑟夫環變式)

POJ - 3517 And Then There Was One (約瑟夫環變式)

題目大意:

      n個人,從第m個人開始報數,報到k的人出局,問最後剩餘的人是第幾號

題解:

     本題和經典的約瑟夫環問題相比,就是從第m個人開始報數了,經典的是從第1個開始

     那我們可以看作,把約瑟夫環左移m次,把第m個人移成第1個人.還要注意這個題是,第m個人首先出局,而不是報k個再出局,所以我們可以看作是從第m-k個人開始報數的

     也就是說,在最後的f[n]+1 變成f[n]+1+m-k

     f[n]+1+m-k萬一k很大就會是負的,所以要給它+n變成正的再取模

     

      我做的時候擔心k可能很大,一次+n有可能不夠,所以就一直+n到結果為正數為止

     其實是不用的,這裡順便學習了一下負數取模

             a%b

     只要a是負的,結果就是負的;‘’只要a是正的,結果就是正的。而不用管b的正負

     並且結果的絕對值一定是[0,b-1]

    所以即使f[n]+1+m-k是個很大值的負數,對n取模之後也是出去[0,n-1],再+n絕對為正

   

    我自己還WA了一發,wa在最後結果ans=0的情況上,因為編號是1-n的,所以ans=0的話其實應該ans=n

寫法1

#include<cstdio>
#include<cstring>
#include<iostream>
#define ll long long
#define INF 1000000007
#define eps 1e-6
#define mod 1000000007
#define double long double
using namespace std;
ll f[100010];
int main()
{
    //freopen("input.txt","r",stdin);
   int n,k,m;
   ll ans;
   while(cin>>n>>k>>m)
   {
       if(n==0 && k==0 && m==0)return 0;
       f[1]=0;
       for(int i=2;i<=n;++i)
        {
            f[i]=(f[i-1]+k)%i;
        }
       ans=f[n]+1+m-k;
       while(ans<0)ans+=n;
       ans%=n;
       if(ans==0)ans=n;
       cout<<ans<<endl;
   }
    return 0;
}

寫法2

#include<cstdio>
#include<cstring>
#include<iostream>
#define ll long long
#define INF 1000000007
#define eps 1e-6
#define mod 1000000007
#define double long double
using namespace std;
ll f[100010];
int main()
{
    //freopen("input.txt","r",stdin);
   int n,k,m;
   ll ans;
   while(cin>>n>>k>>m)
   {
       if(n==0 && k==0 && m==0)return 0;
       f[1]=0;
       for(int i=2;i<=n;++i)
        {
            f[i]=(f[i-1]+k)%i;
        }
       ans=f[n]+1+m-k;
       ans%=n;
       if(ans<=0)ans+=n;
       cout<<ans<<endl;
   }

    return 0;
}