Pertozavodsk Winter Training Camp 2016-Problem J. Sort It!

Time limit: 1.5 seconds
Memory limit: 512 mebibytes

You are given a permutation of length n: p 1 p_{1} p1, p 2 p_{2} p2, . . ., p n p_{n} pn. Consider some array of length n consisting of integers between 1 and n (equal elements are allowed). Let us transform the array in the following manner:
 at first, let us take all elements equal to p1 from it and write them on a piece of paper (if there are no such elements, just do not write anything). Then write all elements equal to p 2 p_{2} p2, then equal to p 3 p_{3} p3and so on, finishing by all elements equal to pn, thus obtaining a new array of length n. For example, if the permutation is 2 1 3 and the array is 2 3 2, the resulting array will be 2 2 3. If after this transformation we get a sorted array, let us call the original array sortable by p. Calculate the total number of arrays that are sortable by p.
As the answer can be very large, output it modulo 1 0 9 10^{9} 109 + 7.

input output
2 2
2 1
3 15
2 1 3

题意
按permutation所给的顺序,将等长度只包含小于n的数组的对应值依次全部拿出来,如果最后的出来的是一个非减序的数组,则方案数加一
题解
先用树状数组求出permutation所有的递增的子序列,用f[i]记录,i表示长度为i的子序列,f[]表示长度为i的子序列的数目,这样用res[i]表示对于一个n的数组只包含i个元素的总数,这样就可以推出 res[i]= i n i^{n} in - ∑ j = 1 i − 1 \sum_{j=1}^{i-1} j=1i1(C i j _{i}^{j} ij *res[j]),总答案就是

  • ∑ i = 1 n \sum_{i=1}^{n} i=1nf[i] * res[i]
#include <bits/stdc++.h>
 
using namespace std;
typedef long long ll;
 
const int maxn = 2e3+9;
const ll mod = 1e9+7;
 
 
int num[maxn],a[maxn];
ll f[maxn];
ll bit[maxn],cnt[maxn];
 
ll C[maxn][maxn];
 
ll res[maxn];
 
void getC(){
    C[0][0]=1;
    for(int i=1;i<=2000;i++){
        C[i][0]=1;
        for(int j=1;j<=i;j++){
            C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod;
        }
    }
}
 
ll q_pow(ll a,ll b){
    ll ans=1;
    while(b){
        if(b&1)ans=ans*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return ans;
}
 
void add(int i,int x){
    while(i<=2000){
        bit[i]=(bit[i]+x)%mod;
        i+=(i&-i);
    }
}
 
ll query(int i){
    ll ans=0;
    while(i){
        ans=(ans+bit[i])%mod;
        i-=(i&-i);
    }
    return ans;
}
 
int main(){
    int n;
    scanf("%d",&n);
    getC();
//    for(int i=1;i<=10;i++){
//        for(int j=1;j<=i;j++){
//            printf("%d ",C[i][j]);
//        }
//        printf("\n");
//    }
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        num[a[i]]=1;
        cnt[a[i]]=1;
        f[1]++;
    }
    for(int i=2;i<=n;i++){
        memset(bit,0,sizeof(bit));
        for(int j=n;j>=1;j--){
            ll x=(query(2000)-query(a[j])+mod)%mod;
            if(num[a[j]]==i-1){
                add(a[j],cnt[a[j]]);
            }
            if(x>0){
                f[i]=(f[i]+x)%mod;
                cnt[a[j]]=x;
                num[a[j]]=i;
            }
        }
    }
    ll ans=0;
    for(int i=1;i<=n;i++){
        res[i]=q_pow(i,n);
        for(int j=1;j<i;j++){
            res[i]=(res[i]-C[i][j]*res[j]%mod+mod)%mod;
        }
        ans=(ans+res[i]*f[i]%mod)%mod;
    }
    printf("%lld\n",ans);
    return 0;
}

你可能感兴趣的:(树状数组,组合数学)