2020牛客暑期多校訓練營(第六場)J Josephus Transform (置換)

https://ac.nowcoder.com/acm/contest/5671/J數組

 

題意:ide

初始有一個1-n的排列,對這個排列進行m次操做,每次操做對排列進行x次k-約瑟夫置換,問m次操做後的序列是什麼。函數

k-約瑟夫置換:n個數圍成一個圈,從第1個開始,數到第k個,將這個數字去掉,操做n次直至圈爲空。數字去掉的順序就是對該排列進行1次k-約瑟夫置換後的序列。spa

 

一個置換能夠定義爲一個函數的複合.net

記f={a1,a2,a3,……an }表示數1-n的一個置換,即 i-->ai,ai<=ncode

對於某一個操做來講,它的x次k-約瑟夫置換對每個數進行的置換都是相同的。blog

好比:7個數進行5次4約瑟夫置換get

      1 2 3 4 5 6 7
一  4 1 6 5 7 3 2
二  5 4 3 7 2 6 1
三  7 5 6 2 1 3 4
四  2 7 3 1 4 6 5
五  1 2 6 4 5 3 7數學

其f={4,1,6,5,7,3,2}string

置換(函數複合)乘法知足乘法結合律

因此只須要獲得第一次的置換結果,對於x次一樣的置換,用快速冪的方式完成便可

 

有關置換羣,能夠去看這篇博文:https://blog.csdn.net/hzk_cpp/article/details/99239041?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param

數學渣渣表示記住結論走人

 

第一次的置換結果就是模擬約瑟夫問題

假設上一個去掉的數字是在剩餘的數中的第x個,去掉以後剩餘m個數字,

那麼這一次選出的數字就是這m個數字中的第(x-1+k)%m 個,若結果爲0就是第m個

上式等價於(x-1+k-1)%m+1

如何獲得剩餘m個數字中的第y個數字?

利用線段樹或者樹狀數組二分

初始每一個位置都是1,表示這個數字尚未去掉

當去掉一個數字時,它的位置減去1

每次二分一個位置,查詢前綴和,直到前綴和爲y

 

而後記第i種操做的置換爲Pi,那麼全部的置換能夠表示爲 (P1^x1)(P2^x2)(P3^x3)……(Pm^xm)

即暴力的求法是 P1*P1……*P1*P2*P2*P2……*Pm*Pm……*Pm  (x1個P1,x2個P2……xm個Pm

快速冪的方式是利用結合律,先將全部的P1算完,再算全部的P2,……最後將m個結果相乘獲得最終結果

相乘的時候注意順序

 

#include<cstdio>
#include<cstring>

using namespace std;

#define N 100001
#define lowbit(x) x&-x

int a[N],tmp[N],to[N],ans[N];

int n,c[N];

void add(int x,int y)
{
    while(x<=n)
    {
        c[x]+=y;
        x+=lowbit(x);
    }
}

int query(int x)
{
    int s=0;
    while(x)
    {
        s+=c[x];
        x-=lowbit(x); 
    } 
    return s;
}

void find_one(int k)
{
    int last=1,now,l,r,mid,pos;
    for(int i=1;i<=n;++i) c[i]=0;
    for(int j=1;j<=n;++j) add(j,1);
    for(int j=1;j<=n;++j)
    {
        pos=(last-1+k-1)%(n-j+1)+1;
        l=1;
        r=n;
        while(l<=r)
        {
            mid=l+r>>1;
            if(query(mid)>=pos) now=mid,r=mid-1;
            else l=mid+1;
        }
        a[j]=now;
        last=query(now);
        add(now,-1);        
    }
}

void mul(int x)
{
    for(int i=1;i<=n;++i) to[i]=i;
    while(x)
    {
        if(x&1) 
        {
            for(int i=1;i<=n;++i) tmp[i]=to[a[i]];
            for(int i=1;i<=n;++i) to[i]=tmp[i];
        }
        x>>=1;
        for(int i=1;i<=n;++i) tmp[i]=a[a[i]];    
        for(int i=1;i<=n;++i) a[i]=tmp[i]; 
    }
    for(int i=1;i<=n;++i) tmp[i]=ans[to[i]];
    for(int i=1;i<=n;++i) ans[i]=tmp[i];
}

int main()
{
    int m,k,x;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i) ans[i]=i;
    for(int i=1;i<=m;++i)
    {
        scanf("%d%d",&k,&x);
        find_one(k);
        mul(x);
    }
    for(int i=1;i<=n;++i) printf("%d ",ans[i]);
}

 

做者: xxy
相關文章
相關標籤/搜索