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

P6144 [USACO20FEB]Help Yourself P

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

Trick:区间覆盖的题要按照左端点排序,记右端点为 r 时的答案为 fr

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

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

对于 k>1,维护答案的 [0,k]的所有值 ,xk(x+1)k=i=0k(ki)xi,预处理系数后 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 @   EricQian06  阅读(18)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示