[gym100956]Problem J. Sort It! BIT+组合数
source : Pertozavodsk Winter Training Camp 2016 Day 1: SPb SU and SPb AU Contest, Friday, January 29, 2016
url:https://codeforces.com/gym/100956/attachments
-----------------------------------------------------
题意:
有一个1~n的全排列p1~pn,问有多少个长度为n的数组,满足
1.数组中每个元素均为1~n的正整数
2.按照全排列的顺序,i从1到n,依次将数组中等于pi的元素拿出来放在新数组末端,完成后新数组为有序的。
-----------------------------------------------------
题解:
样例
3
2 1 3
含1个不同元素的数组:
1:1个
2:1个
3:1个
含2个不同元素的数组:
2,3:2^3-1个
1,3:2^3-1个
解法:
求出原排列中长度为1~n的上升子序列有多少个,记为len[i];
求出严格含1~n个不同元素的n位的数组有多少种,记为f[i];
则ans = sigma(len[i]*f[i])
求len[i]:递推,已知以第j位为结尾的长度为x的上升子序列有sum_prelen[j]个,则以第i位为结尾长度为x+1的上升子序列数量=sigma(sum_prelen[1~i-1])。用树状数组维护。
求f[i]:f[i]=i! - sigma(f[1~i-1])
-------------------------------------------------
代码如下:
1 #include<bits/stdc++.h>
2 using namespace std;
3
4 typedef long long LL;
5 const int N=2010;
6 const LL mod=(LL)1e9+7;
7 int n;
8 LL c[N],sum_prelen[N],len[N],val[N],jc[N],f[N];
9
10 void readin(LL &x)
11 {
12 x=0;bool f=0;char ch=getchar();
13 while(!isdigit(ch)) {
14 f|=(ch=='-');
15 ch=getchar();
16 }
17 while(isdigit(ch)) {
18 x=(x<<3)+(x<<1)+ch-48;
19 ch=getchar();
20 }
21 if(f) x=-x;
22 }
23
24 void add(LL x,LL d){
25 for(int i=x;i<=n;i+=(i&(-i))) c[i]=(c[i]+d)%mod;
26 }
27 LL getsum(LL x){
28 LL ans=0;
29 for(int i=x;i>=1;i-=(i&(-i))) ans=(ans+c[i])%mod;
30 return ans;
31 }
32
33 LL mypow(LL x,LL y){
34 LL ans=1;
35 while(y)
36 {
37 if(y&1) ans=ans*x%mod;
38 x=x*x%mod;
39 y>>=1;
40 }
41 return ans;
42 }
43
44 LL mod_inverse(LL x,LL n){
45 return mypow(x,n-2);
46 }
47
48 LL cal_C(LL x,LL y){
49 // C(x,y)=y!/(x!(y-x)!)
50 return jc[y] * mod_inverse(jc[x],mod) % mod * mod_inverse(jc[y-x],mod) % mod;
51 }
52
53 int main()
54 {
55 freopen("a.in","r",stdin);
56 scanf("%d",&n);
57 for(int i=1;i<=n;i++) readin(val[i]);
58 for(int i=1;i<=n;i++) sum_prelen[i]=1;
59 len[1]=n;
60 for(int i=2;i<=n;i++)
61 {
62 len[i]=0;
63 for(int j=1;j<=n;j++) c[j]=0;
64 for(int j=1;j<=n;j++)
65 {
66 LL sum_nowlen=getsum(val[j]-1);
67 len[i]=(len[i]+sum_nowlen)%mod;
68 add(val[j],sum_prelen[j]);
69 sum_prelen[j]=sum_nowlen;
70 }
71 // for(int j=1;j<=n;j++) printf("%lld ",len[j]);printf("\n");
72 }
73
74 jc[0]=1;for(int i=1;i<=n;i++) jc[i]=(jc[i-1]*((LL)i))%mod;
75 f[0]=0;
76 LL ans=0;
77 for(int i=1;i<=n;i++)
78 {
79 f[i]=mypow(i,n);
80 for(int j=1;j<i;j++)
81 f[i]=((f[i]-cal_C(j,i)*f[j]%mod)%mod+mod)%mod;
82 ans=(ans+len[i]*f[i]%mod)%mod;
83 }
84
85 printf("%I64d\n",ans);
86 return 0;
87 }