题面

传送门

思路

首先,本题目的核心元素是非降子序列,而显然这个题目中的子序列只和序列的长度、位置,以及互相之间的包含关系,这些东西相关

所以我们可以依据这些先“猜”(实际上是估测一个类似的)$dp$方程:

设$dp[i][j]$表示以$i$个位置结尾的,长度为$j$的非降子序列个数

转移:$dp[i][j]=\sum_{k=1}^{i-1}[a[k]<a[i]]dp[k][j-1]$

这个东西显然可以用树状数组求逆序对的套路,在$O(n^2logn)$的时间内求出来

然后,我们定义$g[i]$表示剩下掉$i$个数,得到一个非降子序列的方法数,方程显然:

$g[i]=\sum_{j=1}^{n}dp[j][i]*(i!)$

注意不要漏掉了阶乘,这个是表示组合方法的

但是这个东西是有问题的:在去掉$i$个数的过程中,有可能在去掉第$j(j<i)$个数的时候就已经达成非降子序列、不能继续操作了

那么我们就需要容斥一下

我们令$ans[i]$表示减去了这些不合法方案以后的$g[i]$

考虑一个$j>i$的数对$(j,i)$,如果在$j$处就已经达成的话,方案数等于$ans[j]$,然后我们要从$i$个里面选出来$j-i$个作为在完成以后还删掉了的

那么显然重复的方案数就是$ans[j] \ast C_{j}^{j-i}\ast(j-i)!$

对于所有的$j>i$,把$g[i]$减掉上面那个东西得到$ans[i]$,然后所有$ans[i]$的和就是答案了

Code

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<cassert>
#define ll long long
#define MOD 1000000007
#define rank DEEP_DARK_FANTASY
using namespace std;
inline int read(){
    int re=0,flag=1;char ch=getchar();
    while(ch>'9'||ch<'0'){
        if(ch=='-') flag=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9') re=(re<<1)+(re<<3)+ch-'0',ch=getchar();
    return re*flag;
}
ll qpow(ll a,ll b){
    ll re=1;
    while(b){
        if(b&1) re=re*a%MOD;
        a=a*a%MOD;b>>=1;
    }
    return re;
}
void add(ll &x,ll y){
    x+=y;
    if(x>=MOD)x-=MOD;
}
void dec(ll &x,ll y){
    x-=y;
    if(x<0) x+=MOD;
}
struct BIT{
    ll a[2010];
    BIT(){memset(a,0,sizeof(a));}
    int lowbit(int x){
        return x&(-x);
    }
    void update(int x,ll val){
        for(;x<=2000;x+=lowbit(x)) add(a[x],val);
    }
    ll sum(int x){
        ll re=0;
        for(;x>0;x-=lowbit(x)) add(re,a[x]);
        return re;
    }
}T[2010];
int n,a[2010],rank[2010];ll dp[2010][2010],ans[2010],tmp[2010];
ll f[2010],finv[2010];
inline bool cmp(int l,int r){
    return a[l]<a[r];
}
void init(){
    int i,len=2000;f[0]=f[1]=finv[0]=finv[1]=1;
    for(i=2;i<=len;i++) f[i]=f[i-1]*i%MOD;
    finv[len]=qpow(f[len],MOD-2);
    for(i=len;i>2;i--) finv[i-1]=finv[i]*i%MOD;
}
ll C(ll x,ll y){
    return f[x]*finv[y]%MOD*finv[x-y]%MOD;
}
int main(){
    n=read();int i,j,cnt=0;ll re=0;
    init();
    for(i=1;i<=n;i++) a[i]=read(),rank[i]=i;
    sort(rank+1,rank+n+1,cmp);
    for(i=1;i<=n;i++){
        cnt++;
        while(a[rank[i]]==a[rank[i+1]]) a[rank[i]]=cnt,i++;
        a[rank[i]]=cnt;
    }
    for(i=1;i<=n;i++){
        for(j=i;j>=2;j--){
            dp[i][j]=T[j-1].sum(a[i]);
            T[j].update(a[i],dp[i][j]);
        }
        dp[i][1]=1ll;
        T[1].update(a[i],1ll);
    }
    for(i=1;i<=n;i++)
        for(j=i;j<=n;j++)
            add(tmp[i],dp[j][i]*f[n-i]%MOD);
    for(i=n;i>=1;i--){
        ans[i]=tmp[i];
        for(j=i+1;j<=n;j++)
            dec(ans[i],ans[j]*C(j,j-i)%MOD*f[j-i]%MOD);
        add(re,ans[i]);
    }
    printf("%lld\n",re);
}

[bzoj4361] isn [树状数组+dp+容斥原理]的更多相关文章

  1. BZOJ4361 isn 树状数组、DP、容斥

    传送门 不考虑成为非降序列后停止的限制,那么答案显然是\(\sum\limits_{i=1}^N cnt_i \times (N-i)!\),其中\(cnt_i\)表示长度为\(i\)的非降序列数量 ...

  2. codeforces 597C (树状数组+DP)

    题目链接:http://codeforces.com/contest/597/problem/C 思路:dp[i][j]表示长度为i,以j结尾的上升子序列,则有dp[i][j]= ∑dp[i-1][k ...

  3. hdu 4622 Reincarnation trie树+树状数组/dp

    题意:给你一个字符串和m个询问,问你l,r这个区间内出现过多少字串. 连接:http://acm.hdu.edu.cn/showproblem.php?pid=4622 网上也有用后缀数组搞得. 思路 ...

  4. Codeforces 597C. Subsequences (树状数组+dp)

    题目链接:http://codeforces.com/contest/597/problem/C 给你n和数(1~n各不同),问你长为k+1的上升自序列有多少. dp[i][j] 表示末尾数字为i 长 ...

  5. HDU2227Find the nondecreasing subsequences(树状数组+DP)

    题目大意就是说帮你给出一个序列a,让你求出它的非递减序列有多少个. 设dp[i]表示以a[i]结尾的非递减子序列的个数,由题意我们可以写出状态转移方程: dp[i] = sum{dp[j] | 1&l ...

  6. CodeForces - 314C Sereja and Subsequences (树状数组+dp)

    Sereja has a sequence that consists of n positive integers, a1, a2, ..., an. First Sereja took a pie ...

  7. HDU 6348 序列计数 (树状数组 + DP)

    序列计数 Time Limit: 4500/4000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)Total Subm ...

  8. [Codeforces261D]Maxim and Increasing Subsequence——树状数组+DP

    题目链接: Codeforces261D 题目大意:$k$次询问,每次给出一个长度为$n$的序列$b$及$b$中的最大值$maxb$,构造出序列$a$为$t$个序列$b$连接而成,求$a$的最长上升子 ...

  9. 【XSY2727】Remove Dilworth定理 堆 树状数组 DP

    题目描述 一个二维平面上有\(n\)个梯形,满足: 所有梯形的下底边在直线\(y=0\)上. 所有梯形的上底边在直线\(y=1\)上. 没有两个点的坐标相同. 你一次可以选择任意多个梯形,必须满足这些 ...

随机推荐

  1. turtle画玫瑰花

    import turtle turtle.screensize(400, 300, "pink") turtle.setup(1000, 600) turtle.write('作者 ...

  2. 第三课:PHP 语法

    PHP 脚本在服务器上执行,然后向浏览器发送回纯 HTML 结果. 基础 PHP 语法 PHP 脚本可放置于文档中的任何位置. PHP 脚本以 <?php 开头,以 ?> 结尾: < ...

  3. <Docker学习>2.Centos7安装docker

    Docker CE 支持 64 位版本 CentOS 7,并且要求内核版本不低于 3.10. CentOS 7 满足最低内核的要求,但由于内核版本比较低,部分功能(如 overlay2 存储层驱动)无 ...

  4. 开始体验第一个JAVA程序吧!

    一.准备工作(配置环境) 1.安装JAVA开发工具(JDK) a.下载符合自己电脑系统的Java开发软件:http://www.oracle.com/technetwork/java/javase/d ...

  5. windows系统下用VScode配置远程编辑服务器文件的环境!通过Rmate方法

    虽然公司电脑win可以通过Xshell通过SSH远程连接家中内网linux服务器了,但是只能用vim编辑文件有点不爽. 于是上网查询,windows下使用vscode远程编辑服务器文件的办法.参照博文 ...

  6. C++封装的全部总结

    类 类是对现实生活中一类具有共同特征的事物的抽象 类是面向对象程序设计实现信息封装的基础. 类是一种用户定义类型,也称类类型. 类的实例称为对象. 类的实质是一种数据类型 面向对象原则 以对象为中心, ...

  7. Redis和Mecahe的简介

    Memcache介绍 概念:Memcache是一个高性能,分布式内存对象缓存系统,通过在内存里维护一个统一的巨大的hash表,它能够用来存储各种格式的数据,包括图像.视频.文件以及数据库检索的结果等. ...

  8. Android Html处理器通用类 HtmlUtil

    1.整体分析 1.1.首先看一下源代码,可以直接Copy. public class HtmlUtil { /** * 获取 html 中的纯文本 */ public static String Ht ...

  9. html5兼容处理&sublime text3配置html5环境

    1.为了兼容低版本的浏览器解析不了hmtl5标签,要在html文件中head内引入html5shiv.min.js文件 <!--[if lt IE 9]> <script src=& ...

  10. laravel5.5路由

    目录 1. routes/web.php 2. routes/api.php 3. 重定向路由 4. 路由参数 5. 约束 6. 命名路由 7. 路由组 8 路由模型绑定 9 表单方法伪造 10 访问 ...