4361: isn

题目链接

题目大意:给出一个长度为n的序列A(A1,A2…AN)。如果序列A不是非降的,你必须从中删去一个数,这一操作,直到A非降为止。求有多少种不同的操作方案,答案模10^9+7

题解:f[i][j]表示选取到第i个元素,第i个元素必须选,一共选出了j个元素,选出的元素构成一个不降的子序列的方案数
树状数组dp一下就 O(n2logn)

记g[i]为长度为j的不下降子序列个数, gi=j=inf[j][i]

容易想到枚举长度i, ans+=(ni)!f[i]

但是这样可能会有一些不合法的方案

注意到不合法的方案在最后一步删之前是一个长度为i+1的不下降子序列,那么不合法的方案数为 (ni1)!f[i+1](i+1)

我的收获:吼啊!

#include <bits/stdc++.h>
using namespace std;

#define ll long long

const int N=2005;
const int P=1000000007;

int n;
int a[N],z[N];
ll f[N][N],g[N],fac[N],s[N][N];

inline void add(int id,int pos,ll x)  
{  
    for(;pos<=n;pos+=(pos&(-pos))) (s[id][pos]+=x)%=P;  
}  

inline ll query(int id,int pos)  
{  
    ll ans=0;  
    for(;pos;pos-=(pos&(-pos))) (ans+=s[id][pos])%=P;  
    return ans;  
}

void work()
{
    add(0,1,1);  
    for(int i=1;i<=n;i++) for(int j=i;j>=1;j--)  
    {  
        f[i][j]=query(j-1,a[i])%P;  
        add(j,a[i],f[i][j]);  
    }  
    for(int i=1;i<=n;i++) for(int j=i;j<=n;j++) (g[i]+=f[j][i])%=P;  
    ll ans=0;
    for(int i=1;i<=n;i++) ans=(((ans+g[i]*fac[n-i])%P-g[i+1]*fac[n-i-1]%P*(i+1)%P)%P+P)%P;  
    printf("%lld\n",ans);  
}

void init()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]),z[i]=a[i];
    sort(z+1,z+1+n);int cnt=unique(z+1,z+1+n)-z-1;
    for(int i=1;i<=n;i++) a[i]=lower_bound(z+1,z+1+cnt,a[i])-z;
    fac[0]=1;for(int i=1;i<=n;i++) fac[i]=fac[i-1]*i%P;
}

int main()  
{  
    init();
    work();
    return 0;  
}  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值