2020牛客暑期多校訓練營(第六場) Josephus Transform
阿新 • • 發佈:2020-07-27
2020牛客暑期多校訓練營(第六場) Josephus Transform
題解:
這個和之前牛客的一個題目很像
2020牛客暑期多校訓練營(第二場) [Just Shuffle]
會做那個之後,這個你只要發現這個找操作就是一種置換,所以可以找到這個置換陣列,這個應該是這個題目的難點,可以用二分+樹狀陣列找到這個置換陣列,然後就是多次進行置換即可。
嚴格來說這個題目其實比第二場的這個題目簡單很多,但是時間不夠,沒寫出來。
#include <bits/stdc++.h> using namespace std; const int maxn = 2e5+10; int p[maxn],a[maxn],c[maxn],n,f[maxn],cnt[maxn],b[maxn]; int lowbit(int x){ return x&(-x); } void updata(int i,int k){ //??i????????k while(i <= n){ c[i] += k; i += lowbit(i); } } int getsum(int i){ //?¡§?A[1 - i]???? int res = 0; while(i > 0){ res += c[i]; i -= lowbit(i); } return res; } int Find(int x){ return x==f[x]?x:f[x]=Find(f[x]); } int main(){ int m; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) b[i]=i; while(m--){ int k,x; scanf("%d%d",&k,&x); for(int i=1;i<=n;i++) c[i]=0,f[i]=i,cnt[i]=0; for(int i=1;i<=n;i++) updata(i,1); int l = 1; for(int i=1;i<=n;i++){ int now = n-i+1; int sum = getsum(n)-getsum(l-1),cur = k; if(now<k) cur = k%now; if(!cur) cur+=now; if(sum<cur) cur = cur-sum,l = 1; int lc = 1,rc = n,res = getsum(l-1),pos=0; while(lc<=rc) { int mid = (lc + rc) >> 1; int sum1 = getsum(mid) - res; if (sum1 >= cur) rc = mid - 1,pos=mid; else lc = mid + 1; } a[i]=pos; updata(pos,-1); l = pos; if(Find(i)!=Find(pos)) f[i]=pos; } // for(int i=1;i<=n;i++) printf("a[%d]=%d\n",i,a[i]); for(int i=1;i<=n;i++) cnt[Find(i)]++; for(int i=1;i<=n;i++) { if (!cnt[i]) continue; int len = cnt[i], w = i, now = i; int num = x % len; for (int j = 1; j <= num; j++) w = a[w]; for (int j = 1; j <= len; j++) { p[now] = b[w]; w = a[w], now = a[now]; } } for(int i=1;i<=n;i++) b[i]=p[i]; // for(int i=1;i<n;i++) printf("%d ",p[i]); // printf("%d\n",p[n]); } for(int i=1;i<n;i++) printf("%d ",p[i]); printf("%d\n",p[n]); } /* 4 1 2 1 */