[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 }

 

posted @ 2019-03-10 21:38 拦路雨偏似雪花 阅读(...) 评论(...) 编辑 收藏