P6144 [USACO20FEB]Help Yourself P(DP+线段树)

P6144 [USACO20FEB]Help Yourself P

将线段按照了 \(r\) 排序,设右端点为 \(r\) 的答案为 \(f_r\),发现这样转移非常困难。

\(\color{yellow}{\bigstar\texttt{Trick}}\):区间覆盖的题要按照左端点排序,记右端点为 \(r\) 时的答案为 \(f_r\)

考虑 \(k=1\) 时怎么做,加入一条线段,

  • 对于 \([1,l-1]\)合法 \(f_i\),可以连通块个数加上 \(1\) 累加到 \(f_r\)
  • 对于 \([l,r]\)\(f_i\) 直接累加到 \(f_r\)
  • 对于 \([r+1,n]\)\(f_i\) 数值乘上 \(2\) 后累加到 \(f_i\),这条线段可以选或不选。

对于 \(k>1\),维护答案的 \([0,k]\)的所有值 ,\(x^k\rightarrow (x+1)^k=\sum_{i=0}^k\binom{k}{i}x^i\),预处理系数后 \(\mathcal{O(k)}\) 加即可。

#define Maxn 100005
#define Maxk 11
#define mod 1000000007
int n,m,k;
int C[Maxk][Maxk];
inline int MOD(int x){ return (x>=mod)?(x-mod):x; }
struct Seg
{
	int l,r;
	Seg(int L=0,int R=0):l(L),r(R){}
	bool friend operator < (Seg x,Seg y) { return x.l<y.l; }
}s[Maxn];
struct TREE
{
	int a[Maxk],muti;
	TREE(){ memset(a,0,sizeof(a)),muti=1; }
	inline friend TREE operator + (TREE x,TREE y)
	{
		TREE ret;
		for(int i=0;i<=k;i++) ret.a[i]=MOD(x.a[i]+y.a[i]);
		return ret;
	}
	inline void Push(int x)
		{ for(int i=0;i<=k;i++) a[i]=1ll*a[i]*x%mod; muti=1ll*muti*x%mod; }
};
TREE tree[Maxn<<3],adx;
inline void pushdown(int p)
{
	if(tree[p].muti>1)
		tree[p<<1].Push(tree[p].muti),tree[p<<1|1].Push(tree[p].muti),
		tree[p].muti=1;
}
void change(int p,int nl,int nr,int x)
{
	if(nl==nr) { tree[p]=adx; return; }
	int mid=(nl+nr)>>1; pushdown(p);
	if(mid>=x) change(p<<1,nl,mid,x);
	else change(p<<1|1,mid+1,nr,x);
	tree[p]=tree[p<<1]+tree[p<<1|1];
}
void Times(int p,int nl,int nr,int l,int r)
{
	if(nl>=l && nr<=r) { tree[p].Push(2); return; }
	int mid=(nl+nr)>>1; pushdown(p);
	if(mid>=l) Times(p<<1,nl,mid,l,r);
	if(mid<r) Times(p<<1|1,mid+1,nr,l,r);
	tree[p]=tree[p<<1]+tree[p<<1|1];
}
TREE query(int p,int nl,int nr,int l,int r)
{
	if(nl>=l && nr<=r) return tree[p];
	int mid=(nl+nr)>>1; pushdown(p);
	if(mid>=l && mid<r)
		return query(p<<1,nl,mid,l,r)+query(p<<1|1,mid+1,nr,l,r);
	else if(mid<r) return query(p<<1|1,mid+1,nr,l,r);
	else return query(p<<1,nl,mid,l,r);
}
int main()
{
	C[0][0]=1;
	for(int i=1;i<=10;i++)
	{
		C[i][0]=1;
		for(int j=1;j<=i;j++) C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod;
	}
	n=rd(),k=rd(),m=n<<1;
	for(int i=1,l,r;i<=n;i++) l=rd(),r=rd(),s[i]=Seg(l,r);
	sort(s+1,s+n+1); adx=TREE(),adx.a[0]=1;
	change(1,0,m,0);
	for(int T=1;T<=n;T++)
	{
		Times(1,0,m,s[T].r+1,m);
		adx=query(1,0,m,0,s[T].l-1);
		TREE ret;
		for(int i=0;i<=k;i++) for(int j=0;j<=i;j++)
			(ret.a[i]+=1ll*C[i][j]*adx.a[j]%mod)%=mod;
		adx=ret+query(1,0,m,s[T].l,s[T].r);
		change(1,0,m,s[T].r);
	}
	printf("%d\n",tree[1].a[k]);
	return 0;
}
posted @ 2022-08-14 17:43  EricQian06  阅读(16)  评论(0编辑  收藏  举报