2020牛客暑期多校训练营(第六场) Josephus Transform

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

*/



上一篇:josephus问题->不带头节点的循环链表


下一篇:UVA10774 Repeated Josephus【约瑟夫环+位运算】