物流网站建设案例开发者模式有什么危害
前置知识:康拓展开
逆康拓展开可以求解 1 1 1 ~ n n n的全排列中,字典序第 x x x个的排列。
逆康拓展开
比如,在 1 1 1 ~ 5 5 5的全排列当中,要求按字典序第 107 107 107的排列。
因为在康拓展开时,单调递增的序列算出的结果是 0 0 0,所以要将原数减一。
首先先让 x / x/ x/ ( n − 1 ) ! (n-1)! (n−1)!,也就是 106 / ( 5 − 1 ) ! = 106 / 4 ! = 106 / 24 = 4 … … 10 106/(5-1)!=106/4!=106/24=4……10 106/(5−1)!=106/4!=106/24=4……10,那么就算出有 4 4 4个值比第一个值小,所以第一个值就是 5 5 5。
接着把上次剩下的余数拿来继续除 10 / ( 4 − 1 ) ! = 10 / 3 ! = 10 / 6 = 1 … … 4 10/(4-1)!=10/3!=10/6=1……4 10/(4−1)!=10/3!=10/6=1……4,只有一个数比第二个值小,那么第二个值就是 2 2 2。
下一次, 4 / ( 3 − 1 ) ! = 4 / 2 ! = 4 / 2 = 2 4/(3-1)!=4/2!=4/2=2 4/(3−1)!=4/2!=4/2=2,有两个数比第三个值小,那么第三个值就是 4 4 4,这时候 2 2 2已经被排过了,现在还没有排的元素是 1 1 1, 3 3 3, 4 4 4,故第三大的是 4 4 4。
接着, 0 / ( 2 − 1 ) ! = 0 / 1 = 0 0/(2-1)!=0/1=0 0/(2−1)!=0/1=0,那就是当前没拍过的元素中第 1 1 1大,所以是 1 1 1。
最后就只剩一个 3 3 3,那么最后排完就是 52413 52413 52413
思想就是康拓展开公式的逆用。
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5;
int read(){int x=0,f=1;char c=getchar();while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+c-'0',c=getchar();return x*f;
}
void print(int x){if(x<0)putchar('-'),x=-x;if(x<10){putchar(x+'0');return;}print(x/10);putchar(x%10+'0');
}
int n,k;
int a[N];
int f[N]={1};
signed main(){n=read(),k=read()-1;for(int i=1;i<=n;i++)a[i]=i,f[i]=f[i-1]*i;string s="";for(int i=1;i<=n;i++){int t=k/f[n-i];print(a[t+1]),putchar(' ');for(int i=t+1;i<=n;i++)a[i]=a[i+1];k%=f[n-i];}
}
或者也可以用动态数组。
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5;
int read(){int x=0,f=1;char c=getchar();while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+c-'0',c=getchar();return x*f;
}
void print(int x){if(x<0)putchar('-'),x=-x;if(x<10){putchar(x+'0');return;}print(x/10);putchar(x%10+'0');
}
int n,k;
vector<int>a;
int f[N]={1};
signed main(){n=read(),k=read()-1;for(int i=1;i<=n;i++)a.push_back(i),f[i]=f[i-1]*i;string s="";for(int i=1;i<=n;i++){int t=k/f[n-i];print(a[t]),putchar(' ');a.erase(a.begin()+t);k%=f[n-i];}
}
例题
Cow Line S
这是一道康拓展开加逆康拓展开的板子题。
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e6+5;
int n,m,k;
vector<int>a;
int g[N];
int f[N]={1};
int bit[N];
void update(int x,int p){while(x<=n){bit[x]+=p;x+=x&-x;}
}
int query(int x){int res=0;while(x){res+=bit[x];x-=x&-x;}return res;
}
signed main(){ios::sync_with_stdio(0);cin>>n>>m;for(int i=1;i<=n;i++)f[i]=f[i-1]*i;while(m--){char op;cin>>op;if(op=='P'){cin>>k;k--;string s="";for(int i=1;i<=n;i++)a.push_back(i);for(int i=1;i<=n;i++){int t=k/f[n-i];cout<<a[t]<<' ';a.erase(a.begin()+t);k%=f[n-i];}cout<<'\n';}else{for(int i=1;i<=n;i++)cin>>g[n-i+1];int ans=0;for(int i=1;i<=n;i++){int res=query(g[i]-1);ans+=f[i-1]*res;update(g[i],1);}cout<<ans+1<<'\n';for(int i=1;i<=n;i++)update(g[i],-1);//记得清空树状数组}}
}