hdu 1443 Joseph (約瑟夫環)
題意:約瑟夫環,一共2*k個人,每次報到m出局,前k個是好人,後k個是壞人,求最小的m使得所有的壞人先出局。
解題方案:
模擬,打表,可以維護一個[start,end]區間保護所有的好人,模擬k步。
設p=(m-1)%n,n為當前人數,即p為每次出局的位置(重新排列並對映以後的位置),初始時start=0,end=k-1,第一步以後p位置出局,
0 p+1 0
1 p+2 1
. ... .
.n-1 n-p-2
. 0 n-p-1
p-1 ------重新排列------> . ------對映------> .
p+1 . .
. . .
.
. p-1 n-2
n-1
可以推出第一步後start應由0變為n-p-1,即start=(start-p-1+n)%n,+n以後再%n,是為了處理負數。同理,end=(end-p-1+n)%n。
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <string> #include <cmath> #include <vector> #include <queue> #include <stack> #include <set> #include <map> using namespace std; #define FOR(i,k,n) for(int i=k;i<n;i++) #define FORR(i,k,n) for(int i=k;i<=n;i++) #define scan(a) scanf("%d",&a) #define scann(a,b) scanf("%d%d",&a,&b) #define scannn(a,b,c) scanf("%d%d%d",&a,&b,&c) #define mst(a,n) memset(a,n,sizeof(a)) #define ll long long #define N 15 #define mod 1000000007 #define INF 0x3f3f3f3f const double eps=1e-8; const double pi=acos(-1.0); int ans[N]; bool check(int k,int m) { int s=0,e=k-1; for(int n=2*k;n>k;n--){ int p=(m-1)%n; if(p>=s&&p<=e) return false; s=(s-p-1+n)%n;//+n以後再%n,為了防止負數 e=(e-p-1+n)%n; } return true; } void Init() { FOR(k,1,N){ for(int m=1;;m++){ if(check(k,m)){ ans[k]=m; break; } } } } int main() { //freopen("in.txt","r",stdin); //freopen("out.txt","w",stdout); Init(); int n; while(cin>>n&&n) { printf("%d\n",ans[n]); } return 0; }
通過暴力或上述方法可以得到結果:ans[14]={0,2,7,5,30,169,441,1872,7632,1740,93313,459901,1358657,2504881}
可見m到了後面還是很大的,所以check的複雜度要比較小才不會超時,或者也可以直接將暴力得到的答案打表上去,就可以O(1)了 :)