[BZOJ4361]isn

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

Input
第一行一个整数n。
接下来一行n个整数,描述A。

Output
一行一个整数,描述答案。

Sample Input
4
1 7 5 3

Sample Output
18

HINT
1<=N<=2000


我们设\(f[i][j]\)表示以\(i\)结尾的长度为\(j\)的不下降子序列个数,借助树状数组可以用\(O(n^2\log n)\)的复杂度求出

然后我们设\(g[i]=\sum\limits_{j=1}^nf[j][i]\),表示长度为\(i\)的非降子序列个数,最后对答案的贡献为\(Ans[i]=(n-i)!\times g[i]\)

但这样统计答案是错误的,因为我们在枚举剩下的\((n-i)\)个数的删除序列的时候,存在某一时刻序列已经非降,但是我们没有停下来

考虑如果我们枚举到一个非法的删除序列,那么它一定是通过\((i+1)\)个数删掉一个的得来的,所以我们容斥一下即可

/*program from Wolfycz*/
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define inf 0x7f7f7f7f
#define lowbit(x) ((x)&(-x))
using namespace std;
typedef long long ll;
typedef unsigned int ui;
typedef unsigned long long ull;
inline int read(){
    int x=0,f=1;char ch=getchar();
    for (;ch<'0'||ch>'9';ch=getchar())  if (ch=='-')    f=-1;
    for (;ch>='0'&&ch<='9';ch=getchar())    x=(x<<1)+(x<<3)+ch-'0';
    return x*f;
}
inline void print(int x){
    if (x>=10)     print(x/10);
    putchar(x%10+'0');
}
const int N=2e3,p=1e9+7;
int f[N+10][N+10],tree[N+10][N+10],g[N+10],fac[N+10];
ll val[N+10],list[N+10];
int n,T;
ll Ans;
void insert(int x,int cnt,int v){for (;x<=n;x+=lowbit(x))   tree[x][cnt]=(tree[x][cnt]+v)%p;}
int query(int x,int cnt){
    int res=0;
    for (;x;x-=lowbit(x))   res=(res+tree[x][cnt])%p;
    return res;
}
int main(){
    n=read();
    for (int i=1;i<=n;i++)  val[i]=list[i]=read();
    sort(list+1,list+1+n);
    T=unique(list+1,list+1+n)-list-1;
    for (int i=1;i<=n;i++)  val[i]=lower_bound(list+1,list+1+T,val[i])-list;
    insert(1,0,1);
    for (int i=1;i<=n;i++){
        for (int j=i;j;j--){
            f[i][j]=query(val[i],j-1);
            insert(val[i],j,f[i][j]);
        }
    }
    fac[0]=1;
    for (int i=1;i<=n;i++)  fac[i]=1ll*fac[i-1]*i%p;
    for (int i=1;i<=n;i++)  for (int j=1;j<=n;j++)  g[i]=(g[i]+f[j][i])%p;
    for (int i=1;i<=n;i++)  Ans=((Ans+1ll*g[i]*fac[n-i]%p-1ll*g[i+1]*fac[n-i-1]%p*(i+1)%p)+p)%p;
    printf("%lld\n",Ans);
    return 0;
}

转载于:https://www.cnblogs.com/Wolfycz/p/10031313.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值