标签: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