POJ - 3517 And Then There Was One (約瑟夫環變式)
阿新 • • 發佈:2018-12-01
題目大意:
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;
}