码迷,mamicode.com
首页 > 其他好文 > 详细

[USACO20FEB]Help Yourself P 题解

时间:2021-02-17 14:07:20      阅读:0      评论:0      收藏:0      [点我收藏+]

标签:c++   fine   space   题目   排列   ref   def   add   操作   

题目链接https://www.luogu.com.cn/problem/P6144

题意:

已经描述的很清楚了,略。

题解:

考虑 \(K=1\) 时的做法:

此时如果沿用 G 组该题的简单做法,是行不通的。

不过仍然是类似的做法,以每个区间结尾的贡献的和。

考虑区间 \([l,r]\)

因为以这个区间结尾,先以 \(l\) 升序排列。

若前面的区间 \(r‘\in[1,l-1]\) ,则联通块个数会加一,为这些加一之和。

\(r‘\in[l,r-1]\) ,则连通块个数不变,为这些之和。

\(r‘\in[r+1,2N]\) ,则是没法按这个区间来统计贡献的,而这个区间选不选两种情况,可以把后缀乘二。

于是,可以用线段树来维护这些操作。

接下来考虑 \(K\) 更大的情况:

发现第二、三种情况都很好实现。

而第一种情况可以用二项式定理展开:

\((x+1)^K=\sum_{i=0}^{K}\binom{K}{i}x^i\)

不过是有若干个这个东西之和,所以 \(x\) 的各个幂都要同时再线段树上维护,这样仍然符合性质。

一点点细节:在 \(0\) 处放一个 \(x^0=1\) 的东西。

当做板子题看待这道题吧。

时间复杂度: \(O(NK\log N+NK^2)\)

代码:

#include <bits/stdc++.h>
#define fi first
#define se second
#define lc pos<<1
#define rc pos<<1|1
using namespace std;
const int N=1e6,K=15,mod=1e9+7;
int n,k,m,c[K][K],tag[N];
pair<int,int> a[N];
struct sb{
	int x[K];
	sb operator + (const sb&y) const {
		sb res;
		for(int i=0;i<=k;i++) res.x[i]=(x[i]+y.x[i])%mod;
		return res; 
	}
	sb operator * (const int&y) const {
		sb res;
		for(int i=0;i<=k;i++) res.x[i]=1ll*x[i]*y%mod;
		return res; 
	}
}tmp,tr[N];
void pushup(int pos) {tr[pos]=tr[lc]+tr[rc];}
void pushdown(int pos){
	if(tag[pos]==1) return;
	int&md=tag[pos];
	tag[lc]=1ll*tag[lc]*md%mod;tag[rc]=1ll*tag[rc]*md%mod;
	tr[lc]=tr[lc]*md;tr[rc]=tr[rc]*md;md=1;
}
void add(int l,int r,int pos,int p,sb x){
	if(l==r) return (void)(tr[pos]=tr[pos]+x);
	pushdown(pos);int mid=l+r>>1;
	if(p<=mid) add(l,mid,lc,p,x);else add(mid+1,r,rc,p,x);pushup(pos);
}
void mul(int l,int r,int pos,int L,int R){
	if(L>R) return;
	if(L<=l&&r<=R) return (void)(tag[pos]=tag[pos]*2%mod,tr[pos]=tr[pos]*2);
	pushdown(pos);int mid=l+r>>1;
	if(L<=mid) mul(l,mid,lc,L,R);if(R>mid) mul(mid+1,r,rc,L,R);pushup(pos);
}
sb query(int l,int r,int pos,int L,int R){
	if(L>R) return fill_n(tmp.x,K,0),tmp;
	if(L<=l&&r<=R) return tr[pos];
	pushdown(pos);int mid=l+r>>1;sb res;fill_n(res.x,K,0);
	if(L<=mid) res=res+query(l,mid,lc,L,R);if(R>mid) res=res+query(mid+1,r,rc,L,R);
	return res;
}
signed main(){
	scanf("%d%d",&n,&k);m=n*2;
	for(int i=0;i<=k;i++) c[i][0]=1;
	for(int i=1;i<=k;i++)
		for(int j=1;j<=i;j++) c[i][j]=c[i-1][j]+c[i-1][j-1];
	for(int i=1;i<=n;i++) scanf("%d%d",&a[i].fi,&a[i].se);
	sort(a+1,a+n+1);tmp.x[0]=1;add(0,m,1,0,tmp);
	for(int t=1;t<=n;t++){
		int l=a[t].fi,r=a[t].se;
		tmp=query(0,m,1,0,l-1);sb res;
		for(int i=0;i<=k;i++){
			res.x[i]=0;
			for(int j=0;j<=i;j++) (res.x[i]+=1ll*c[i][j]*tmp.x[j]%mod)%=mod;
		}
		tmp=query(0,m,1,l,r-1);res=res+tmp;
		add(0,m,1,r,res);mul(0,m,1,r+1,m);
	}
	printf("%d\n",query(0,m,1,0,m).x[k]);
	return 0;
}

[USACO20FEB]Help Yourself P 题解

标签:c++   fine   space   题目   排列   ref   def   add   操作   

原文地址:https://www.cnblogs.com/shrshrshr/p/14401154.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!