【USACO20FEB】Help Yourself P(线段树)(二项式展开)

传送门


题解:

首先这种求 k k k 次幂, k k k又那么小,显然就是二项式展开维护各个自然幂之和。

于是一个比较显然的想法就是考虑一个一个加入,那么会有一部分不变,另一部分+1,维护总和和其中某个部分即可。

按照左端点排序加入,维护一下右端点的前缀和即可。


代码:

#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const

namespace IO{
	inline char gc(){
		static cs int Rlen=1<<22|1;static char buf[Rlen],*p1,*p2;
		return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
	}template<typename T>T get_integer(){
		char c;bool f=false;while(!isdigit(c=gc()))f=c=='-';T x=c^48;
		while(isdigit(c=gc()))x=((x+(x<<2))<<1)+(c^48);return f?-x:x; 
	}inline int gi(){return get_integer<int>();} 
}using namespace IO;

using std::cerr;
using std::cout;
typedef std::pair<int,int> pii;
#define l first
#define r second 

cs int mod=1e9+7;
inline int add(int a,int b){return a+b>=mod?a+b-mod:a+b;}
inline int dec(int a,int b){return a-b<0?a-b+mod:a-b;}
inline int mul(int a,int b){ll r=(ll)a*b;return r>=mod?r%mod:r;}
inline void Inc(int &a,int b){a+=b-mod;a+=a>>31&mod;}
inline void Dec(int &a,int b){a-=b;a+=a>>31&mod;}
inline void Mul(int &a,int b){a=mul(a,b);}

cs int N=1e5+7;

int n,k;pii p[N];
int id[N+N],sm[17],pr[17];
int pw[N][17],nw;

int C[17][17];

struct atom{
	int a[11];atom(){}
	int& operator[](int o){return a[o];}
	cs int& operator[](int o)cs{return a[o];}
	void plus(){
		for(int re i=0;i<=k;++i)
			Inc(a[i],a[i]);
	}
}; 

atom operator+(cs atom &a,cs atom &b){
	atom c;
	for(int re i=0;i<=k;++i)
		c[i]=add(a[i],b[i]);
	return c;
}

atom& operator*=(atom &a,int b){
	for(int re i=0;i<=k;++i)
		Mul(a[i],b);
	return a;
}

namespace SGT{

cs int N=::N<<3|7;

#define lc u<<1
#define rc lc|1
atom vl[N];int tim[N];

void init(){std::fill(tim,tim+N,1);}

void push_up(int u){vl[u]=vl[lc]+vl[rc];}
void push_tim(int u,int t){
	vl[u]*=t;Mul(tim[u],t);
}void push_dn(int u){
	if(tim[u]!=1){
		push_tim(lc,tim[u]);
		push_tim(rc,tim[u]);
		tim[u]=1;
	}
}

atom qy(int u,int l,int r,int ql,int qr){
	if(ql<=l&&r<=qr)return vl[u];
	int mid=(l+r)>>1;push_dn(u);
	if(qr<=mid)return qy(lc,l,mid,ql,qr);
	if(mid<ql)return qy(rc,mid+1,r,ql,qr);
	return qy(lc,l,mid,ql,qr)+qy(rc,mid+1,r,ql,qr);
}

void ad(int u,int l,int r,int p,cs atom &t){
	if(l==r){vl[u]=vl[u]+t;return ;}
	int mid=(l+r)>>1;push_dn(u);
	p<=mid?ad(lc,l,mid,p,t):ad(rc,mid+1,r,p,t);
	push_up(u);
}

void plus(int u,int l,int r,int ql,int qr){
	if(ql<=l&&r<=qr)return push_tim(u,2);
	int mid=(l+r)>>1;push_dn(u);
	if(ql<=mid)plus(lc,l,mid,ql,qr);
	if(mid<qr)plus(rc,mid+1,r,ql,qr);
	push_up(u);
}

}

void Main(){
	n=gi(),k=gi();
	for(int re i=0;i<=k;++i){
		C[i][0]=1;
		for(int re j=1;j<=i;++j)
			C[i][j]=add(C[i-1][j],C[i-1][j-1]);
	}for(int re i=1;i<=n;++i)
		p[i].l=gi(),p[i].r=gi();
	std::sort(p+1,p+n+1);
	for(int re i=1;i<=n;++i)
		id[p[i].r]=i;
	sm[0]=1;pw[0][0]=1;pr[0]=1;
	SGT::init();
	for(int re i=1;i<=n;++i){
		atom tmp=SGT::qy(1,1,n+n,p[i-1].l,p[i].l);
		for(int re t=0;t<=k;++t)
			Inc(pr[t],tmp[t]),tmp[t]=0;
		for(int re K=0;K<=k;++K)
			for(int re t=0;t<=K;++t)
				Inc(tmp[K],mul(C[K][t],pr[t]));
		SGT::ad(1,1,n+n,p[i].r,tmp);
		for(int re t=0;t<=k;++t)
			Inc(sm[t],add(tmp[t],dec(sm[t],pr[t])));
		tmp=SGT::qy(1,1,n+n,p[i].l,p[i].r-1);
		SGT::ad(1,1,n+n,p[i].r,tmp);
		SGT::plus(1,1,n+n,p[i].r+1,n+n);
	}cout<<sm[k]<<"\n";
}

inline void file(){
#ifdef zxyoi
	freopen("b.in","r",stdin);
#else 
#ifndef ONLINE_JUDGE
	freopen("b.in","r",stdin);
	freopen("b.out","w",stdout);
#endif
#endif
}signed main(){file();Main();return 0;} 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值