【BZOJ4361】isn 动态规划+树状数组+容斥

【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

题解:想到动归+树状数组+容斥,但是容斥系数想复杂了~

我们希望先求出所有长度为i的非降序列个数,可以用DP解决。设f[i][j]表示最大值为i,长度为j的非降序列个数,用树状数组优化转移即可。

然后用g[i]表示$\sum f[..][j]$。因为其它数删除的顺序可以随便选,所以g[i]*=(n-i)!。但是有可能删到一半就已经得到了一个非降序列,怎么除去不合法状态呢?容斥呗!

一开始想了半天容斥系数,但其实g[i]-=g[i+1]*(i+1)即可。因为删到一般就得到非降序列情况刚好是g[i+1]。

时间复杂度$O(n\log n)$

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int P=1000000007;
int n,m;
ll ans;
int val[2010],v[2010],p[2010];
int s[2010][2010];
ll f[2010],c[2010][2010],jc[2010],jcc[2010],ine[2010];
inline int rd()
{
	int ret=0,f=1;	char gc=getchar();
	while(gc<‘0‘||gc>‘9‘)	{if(gc==‘-‘)	f=-f;	gc=getchar();}
	while(gc>=‘0‘&&gc<=‘9‘)	ret=ret*10+(gc^‘0‘),gc=getchar();
	return ret*f;
}
bool cmp(const int &a,const int &b)
{
	return val[a]<val[b];
}
inline void updata(int x,int y,int z)
{
	if(!z)	return ;
	f[y]+=z;
	for(int i=x;i<=m;i+=i&-i)
	{
		s[y][i]+=z;
		if(s[y][i]>=P)	s[y][i]-=P;
	}
}
inline int query(int x,int y)
{
	int i,ret=0;
	for(i=x;i;i-=i&-i)
	{
		ret+=s[y][i];
		if(ret>=P)	ret-=P;
	}
	return ret;
}
int main()
{
	n=rd();
	int i,j;
	jc[0]=jc[1]=jcc[0]=jcc[1]=ine[0]=ine[1]=1;
	for(i=2;i<=n;i++)	jc[i]=jc[i-1]*i%P,ine[i]=P-(P/i)*ine[P%i]%P,jcc[i]=jcc[i-1]*ine[i]%P;
	for(i=0;i<=n;i++)
	{
		c[i][0]=1;
		for(j=1;j<=i;j++)	c[i][j]=(c[i-1][j-1]+c[i-1][j])%P;
	}
	for(i=1;i<=n;i++)	val[i]=rd(),p[i]=i;
	sort(p+1,p+n+1,cmp);
	for(i=1;i<=n;i++)
	{
		if(i==1||val[p[i]]>val[p[i-1]])	m++;
		v[p[i]]=m;
	}
	for(i=1;i<=n;i++)
	{
		for(j=i;j>=2;j--)	updata(v[i],j,query(v[i],j-1));
		updata(v[i],1,1);
	}
	for(i=1;i<=n;i++)	f[i]=f[i]%P*jc[n-i]%P;
	for(i=1;i<=n;i++)	f[i]=(f[i]-f[i+1]*(i+1)%P+P)%P,ans=(ans+f[i])%P;
	printf("%lld",ans);
	return 0;
}//4 1 2 3 4
时间: 2024-10-05 23:55:18

【BZOJ4361】isn 动态规划+树状数组+容斥的相关文章

4.4 省选模拟赛 拉格朗日计数 树状数组+容斥.

像这种计数 问题什么的 是最讨厌的了... 考虑是环往环后面再续一段 暴力枚举前两个数字 树状数组统计第三个数的个数 n^2log. 考虑只枚举第个数 发现由于边界问题什么的很难处理. 再将枚举直接放到环上 发现边界问题没有了 不过存在 枚举第二个数之后 有 123 231 312 这三种形式. 第一种形式很好统计 预处理一下左边有多少个数字比自己小即可. 考虑第二种和第三种形式 很难在枚举2的时候统计出来这两种形式 考虑容斥 231=XX1-321. 312=3XX-321. 发现XX1和3X

【bzoj1109】[POI2007]堆积木Klo 动态规划+树状数组

题目描述 Mary在她的生日礼物中有一些积木.那些积木都是相同大小的立方体.每个积木上面都有一个数.Mary用他的所有积木垒了一个高塔.妈妈告诉Mary游戏的目的是建一个塔,使得最多的积木在正确的位置.一个上面写有数i的积木的正确位置是这个塔从下往上数第i个位置.Mary决定从现有的高塔中移走一些,使得有最多的积木在正确的位置.请你告诉Mary她应该移走哪些积木. 输入 第一行为一个数n,表示高塔的初始高度.第二行包含n个数a1,a2,...,an,表示从下到上每个积木上面的数. 输出 注意:请

BZOJ1264 [AHOI2006]基因匹配Match 动态规划 树状数组

欢迎访问~原文出处--博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ1264 题意概括 给出两个长度为5*n的序列,每个序列中,有1~n各5个. 求其最长公共子序列长度. 题解 我们发现这题的序列特殊性是关键! 我们只需要知道每一种数字在某一个序列中的5个位置,然后对于普通的LCS问题,我们只有在a[i] = b[j]的时候才会+1. 那么我们可以维护一个树状数组,在a序列中,我们一个一个位置扫过去,每次通过树状数组维护的前缀最大值来更新,然后因为修改不多,所以维护

BZOJ 1264 AHOI2006 基因匹配Match 动态规划+树状数组

题目大意:给定n个数和两个长度为n*5的序列,每个数恰好出现5次,求两个序列的LCS n<=20000,序列长度就是10W,朴素的O(n^2)一定会超时 所以我们考虑LCS的一些性质 LCS的决策+1的条件是a[i]==b[j] 于是我们记录a序列中每个数的5个位置 扫一下b[i] 对于每个b[i]找到b[i]在a中的5个位置 这5个位置的每个f[pos]值都可以被b[i]更新 于是找到f[1]到f[pos-1]的最大值+1 更新f[pos]即可 这个用树状数组维护 时间复杂度O(nlogn)

#46 delete(动态规划+树状数组)

二维的dp非常显然,但这也没有什么优化的余地了. 注意到最后的方案中只有产生贡献的位置是有用的,剩下的部分可以在该范围内任意选取. 所以我们考虑设f[i]为i号位最后产生贡献的答案,则f[i]=max{f[j]+1} (i-j>=a[i]-a[j],a[i]>a[j]). 观察这个限制,即为i-a[i]>=j-a[j]且a[i]>a[j],以及i>j.可以发现这里i>j的限制是可以被前两个限制所包含的.于是我们考虑换个顺序dp,按照a[i]从小到大来.树状数组维护即可.

树状数组复习

今天重新复习了一下树状数组- -发现真的是一个很简洁的东西 引用请注明出处:http://blog.csdn.net/int64ago/article/details/7429868 写下这个标题,其实心里还是没底的,与其说是写博帖,不如说是做总结.第一个接触树状数组还是两年前,用什么语言来形容当时的感觉呢?……太神奇了!真的,无法表达出那种感觉,她是那么的优雅,10行不到的代码,却把事情干的如此出色!没有了解她原理的前提下即使把代码倒背如流也理解不了!其中,我就是一直没搞懂地在使用她.时隔两年

树状数组详解(图形学算法)

目录 一.从图形学算法说起 1.Median Filter 概述 2.r pixel-Median Filter 算法 3.一维模型 4.数据结构的设计 5.树状数组华丽登场 二.细说树状数组 1.树 or 数组? 2.结点的含义 3.求和操作 4.更新操作 5.lowbit函数O(1)实现 6.小结 三.树状数组的经典模型 1.PUIQ模型 2.IUPQ模型 3.逆序模型 4.二分模型 5.再说Median Filter 6.多维树状数组模型 四.树状数组题集整理 一.从图形学算法说起 1.M

bzoj4361:isn(dp+容斥+树状数组)

题面 darkbzoj 题解 \(g[i]\)表示长度为\(i\)的非降序列的个数 那么, \[ ans = \sum_{i=1}^{n}g[i]*(n-i)!-g[i+1]*(n-i-1)!*(i+1) \] 怎么求\(g[i]\)呢 设\(f[i][j]\)为长度为\(i\)的非降序列,以最后一个数是\(j\)的数量 \(f[i][j] = \sum f[i-1][k](k<=j)\) 这样是\(O(n^3)\) 因为带修改,所以树状数组优化转移 复杂度:\(O(n^2logn)\) Cod

hdu-5792 World is Exploding(容斥+树状数组)

题目链接: World is Exploding Time Limit: 2000/1000 MS (Java/Others)     Memory Limit: 65536/65536 K (Java/Others) Problem Description Given a sequence A with length n,count how many quadruple (a,b,c,d) satisfies: a≠b≠c≠d,1≤a<b≤n,1≤c<d≤n,Aa<Ab,Ac>A