「BZOJ3688」折线统计 题解

熬煞我的97行代码

DP分析

· 状态:使用三元组 \(f(i,j,false/true)\) 表示在前 \(i\) 个点中,选取了 \(j\) 条线段,其中最后一条线段是下降 \((false)\) 或上升 \((true)\) 的方案数;
· 目标:$$f(n,k,false)+f(n,k,true)$$
· 状态转移方程

\[ \left\{ \begin{aligned} f(i,j,false) & = \Sigma\{ f(k,j,false), f(k,j-1,true) \} & (k<i , a[k].y>a[i].y)\\ \\ f(i,j,true) & = \Sigma\{ f(k,j,true), f(k,j-1,false) \} & (k<i , a[k].y>a[i].y) \end{aligned} \right. \]

· 当然逃不过树状数组优化

具体实现

\(a\) 数组沿X轴排序,并对Y轴进行离散化。

struct XOY{
	int x,y;
	friend bool operator<(XOY fir,XOY sec){
		return fir.x<sec.x;
	}
}a[maxn];

出于未知的幻想,鄙人先使用了二叉搜索树对 \(a.y\) 离散化:

struct BSTree{
	struct BSTree_node{
		int num;
		bool vis;
		int l,r;
	}b[maxn];
	int tot,a_tot;
	inline void f(){
		tot=1;//最容易忘掉的头疼东西
		a_tot=0;
	}
	inline void push(int k,int x){//存树
		if(!b[k].vis){
			b[k].num=x;
			b[k].vis=true;
			return ;
		}else if(x<=b[k].num){//大的相等的存左儿子
			if(!b[k].l)b[k].l=++tot;//没儿子,添加节点,到最后b的顺序会惊喜地等于a.y的顺序
			push(b[k].l,x);
		}else if(x>b[k].num){//小的存右儿子
			if(!b[k].r)b[k].r=++tot;
			push(b[k].r,x);
		}
	}
	inline void disc(int k){//离散
		if(!b[k].vis)return ;
		disc(b[k].l);
		a[k].y=++a_tot;
		disc(b[k].r);
	}
}bst;

main:

bst.f();
for(int i=1;i<=n;i++){
	a[i].x=read();a[i].y=read();
	bst.push(1,a[i].y);
}
bst.disc(1);
sort(a+1,a+1+n);

使用树状数组 \(t(j,false/true)\) 省略第一维:

struct BITree{
	int c[maxn];
	inline int lowbit(int x){return x&(-x);}
	inline void add(int x,int val){
		val=(val%mod+mod)%mod;//这个特别重要,下文解释
		while(x<=n){
			c[x]=(c[x]+val)%mod;
			x+=lowbit(x);
		}
	}
	inline int query(int x){
		int ret=0;
		while(x){
			ret=(c[x]+ret)%mod;
			x-=lowbit(x);
		}
		return ret;
	}
}t[11][2];

main:

for(int i=1;i<=n;i++){
	t[0][0].add(a[i].y,1);
	t[0][1].add(a[i].y,1);
	for(int j=1;j<=k;j++){
		int tmpa=t[j][0].query(n)-t[j][0].query(a[i].y);
		int tmpb=t[j-1][1].query(n)-t[j-1][1].query(a[i].y);
		int tmpc=t[j][1].query(a[i].y-1)+t[j-1][0].query(a[i].y-1);
		t[j][0].add(a[i].y,tmpa+tmpb);
		t[j][1].add(a[i].y,tmpc);
	}
}

有一点差点把我卡惑了:

val=(val%mod+mod)%mod;

这个语句在 BITree.add(int x,int val) 中,需要注意的是,用 tmpa+tmpb 传导的 val 中有减法,而 tmpatmpb 获取的值本身是进行过 mod ,所以不可以直接 val%=mod

举个例子:

比如 x=21 , y=19 , mod=5
那么 val 应该为 (21-19)% 5 = 2;
而事实上,x在 BITree 中取模后值为 1,y值为 4
此时 val 应该为 (1-4+5)% 5 = 2;而不是(1-4)% 5 = 2;

完整 AC Code

#include<bits/stdc++.h>
using namespace std;
const int maxn=50010;
const int mod=1e5+7;
inline int read(){
	int x=0,f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-')f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9'){
		x=(x<<1)+(x<<3)+(ch^48);
		ch=getchar();
	}
	return x*f;
}
int n,k;
struct BITree{
	int c[maxn];
	inline int lowbit(int x){return x&(-x);}
	inline void add(int x,int val){
		val=(val%mod+mod)%mod;
		while(x<=n){
			c[x]=(c[x]+val)%mod;
			x+=lowbit(x);
		}
	}
	inline int query(int x){
		int ret=0;
		while(x){
			ret=(c[x]+ret)%mod;
			x-=lowbit(x);
		}
		return ret;
	}
}t[11][2];
struct XOY{
	int x,y;
	friend bool operator<(XOY fir,XOY sec){
		return fir.x<sec.x;
	}
}a[maxn];
struct BSTree{
	struct BSTree_node{
		int num;
		bool vis;
		int l,r;
	}b[maxn];
	int tot,a_tot;
	inline void f(){
		tot=1;
		a_tot=0;
	}
	inline void push(int k,int x){
		if(!b[k].vis){
			b[k].num=x;
			b[k].vis=true;
			return ;
		}else if(x<=b[k].num){
			if(!b[k].l)b[k].l=++tot;
			push(b[k].l,x);
		}else if(x>b[k].num){
			if(!b[k].r)b[k].r=++tot;
			push(b[k].r,x);
		}
	}
	inline void disc(int k){
		if(!b[k].vis)return ;
		disc(b[k].l);
		a[k].y=++a_tot;
		disc(b[k].r);
	}
}bst;
int main(){
	n=read();k=read();
	bst.f();
	for(int i=1;i<=n;i++){
		a[i].x=read();a[i].y=read();
		bst.push(1,a[i].y);
	}
	bst.disc(1);
	sort(a+1,a+1+n);
	for(int i=1;i<=n;i++){
		t[0][0].add(a[i].y,1);
		t[0][1].add(a[i].y,1);
		for(int j=1;j<=k;j++){
			int tmpa=t[j][0].query(n)-t[j][0].query(a[i].y);
			int tmpb=t[j-1][1].query(n)-t[j-1][1].query(a[i].y);
			int tmpc=t[j][1].query(a[i].y-1)+t[j-1][0].query(a[i].y-1);
			t[j][0].add(a[i].y,tmpa+tmpb);
			t[j][1].add(a[i].y,tmpc);
		}
	}
	printf("%d\n",(t[k][0].query(n)+t[k][1].query(n))%mod);
	return 0;
} 

97行万岁

$$-----END------$$

posted @ 2021-11-06 11:31  AlienCollapsar  阅读(99)  评论(0)    收藏  举报
// 生成目录索引列表 // ref: http://www.cnblogs.com/wangqiguo/p/4355032.html // modified by: zzq