康托展开模板(树状数组维护)O (n log n)
2016-08-18 19:27
225 查看
很早以前就接触过了康托展开,只是当时完全是死背公式的,用不了多久就忘了。直到最近又遇到了,才想到要彻底地弄懂——于是只花了一分钟就懂了。
那么最最最普通的做法就是每次用O(n)的时间找到i位置后的比i位置上这个数小的数的个数,乘上(n−i)!,不要忘记下标是从1开始的,所以求出的结果加上1。
这个算法时间复杂度是O(n2)
当n=10000时,就难以接受了。
我们对ai进行标记,1是没有扫过,0是扫过了,那可以用树状数组维护一个前缀和,就能知道<ai且没有被扫过的点的个数了。
Code:
那么最最最普通的做法就是每次用O(n)的时间找到i位置后的比i位置上这个数小的数的个数,乘上(n−i)!,不要忘记下标是从1开始的,所以求出的结果加上1。
这个算法时间复杂度是O(n2)
当n=10000时,就难以接受了。
我们对ai进行标记,1是没有扫过,0是扫过了,那可以用树状数组维护一个前缀和,就能知道<ai且没有被扫过的点的个数了。
Code:
#include<cstdio> #define fo(i,x,y) for(int i=x;i<=y;i++) #define low(x) x&-x #define ll long long #define mo 1000000007 #define max 1000000 using namespace std; ll n,ans,b[max+1],c[max+1],fac[max+1]; void ch(int x,int p) { while(x<=n) { c[x]+=p; x+=low(x); } } ll sum(int x) { ll s=0; while(x>0) { s+=c[x]; x-=low(x); } return s; } void Cantor_unfold() { ans=1; fo(i,1,n) { ans=(ans+(fac[n-i]*sum(b[i]-1))%mo)%mo; ch(b[i],-1); } } int main() { fac[0]=1; fo(i,1,max) fac[i]=(fac[i-1]*(ll)i)%mo; scanf("%lld",&n); fo(i,1,n) scanf("%lld",&b[i]),ch(i,1); Cantor_unfold(); printf("%lld",ans); }
相关文章推荐
- P3368 【模板】树状数组 2(树状数组维护差分序列)
- 树状数组-线段树模板题(leetcode-307)
- 树状数组求逆序数的模板(离散化处理)
- HDU 1166 敌兵布阵 (我的树状数组加线段树点修改模板)
- 洛谷 P3374 【模板】树状数组 1
- HDU 1166 线段树模板&树状数组模板
- poj 1195 二维树状数组 及二维树状数组模板
- 模板(线段树 + 树状数组 + 单点查询 + 区间查询)eg:HDU 1754 - I Hate It
- HDU 3966 树链剖分+树状数组 模板
- [BZOJ1935][SHOI2007]Tree 园丁的烦恼(离线+动态维护树状数组)
- 树状数组模板
- 【NOIP模板】 树状数组
- 树状数组【模板】
- 树状数组模板
- 康托展开模板
- 树状数组模板及poj几道简单题
- 树状数组模板
- 树状数组维护区间最大值
- 树状数组模板1——单点修改区间查询
- [BZOJ1103][POI2007]大都市meg(树状数组维护树上差分)