比赛时,第二题就是做的这个,当时果断没仔细考虑,直接用线段树暴力求。结果易想而知,超时了。
比赛后搜了搜题解,恍然大悟。
思路:显然用线段树,但是由于每次查询都会有变,所以不可能存储题目中的式子。
这里要注意:k的值非常小,所以应该是将式子按二项式定理展开
(i-L+1)^k=(i+(1-L))^k
展开之后可以发现:我们可以在节点存储ai*i,ai*i^2,ai*i^3,ai*i^4,ai*i^5 (L<=i<=R)的累加和。
至于关于(1-L)^j(j=0~5)可以预先枚举所有的L,预先处理一下用数组存储。
展开式要用到组合,所以组合也要预先处理一下。
当更新时,我们发现l<=i<=r区间中所有的ai都变为x,
累加和分别为x*(L+...+R),x*(L^2+...+R^2),x*(L^3+...+R^3),...,x*(L^5+...+R^5)
因此我们也要预先处理1^j+2^j+...+n^j的和,存到一个数组中去
#include <iostream> #include <algorithm> #include <stdio.h> #include <string.h> #include <queue> using namespace std; const long long mod=1000000007; const int maxn=4*100010; const int maxnN=100005; int n,m,k; int L,R; long long ans; int C[6][6]; long long S[maxnN][6]; //S[i][j]存储(1-i)^j的值 long long LMi[maxnN][6]; //LMi[i][j]存储i^j的值,1<=i<=n,即ai*i^j中的i^j long long sum[maxnN][6]; //sum[i][j] 表示1^j+2^j……+i^j的值 struct Node { int left,right; long long pow0,pow1,pow2,pow3,pow4,pow5; //powj: ai*i^j的和,j=0~5 bool lazy; int add; } tree[maxn]; void init1() { C[0][0]=1; for(int i=1; i<=5; i++) { C[i][0]=1; C[i][i]=1; for(int j=1; j<i; j++) { C[i][j]=C[i-1][j-1]+C[i-1][j]; } } } void init2() { memset(sum,0,sizeof(sum)); for(int i=1; i<=n; i++) { S[i][0]=1; LMi[i][0]=1; sum[i][0]=i; for(int j=1; j<=5; j++) { LMi[i][j]=(LMi[i][j-1]*i)%mod; S[i][j]=(S[i][j-1]*(1-i)%mod+mod)%mod; sum[i][j]=(sum[i-1][j]+LMi[i][j])%mod; } } } void pushUp(int rt) { tree[rt].pow0=(tree[rt<<1].pow0+tree[rt<<1|1].pow0)%mod; tree[rt].pow1=(tree[rt<<1].pow1+tree[rt<<1|1].pow1)%mod; tree[rt].pow2=(tree[rt<<1].pow2+tree[rt<<1|1].pow2)%mod; tree[rt].pow3=(tree[rt<<1].pow3+tree[rt<<1|1].pow3)%mod; tree[rt].pow4=(tree[rt<<1].pow4+tree[rt<<1|1].pow4)%mod; tree[rt].pow5=(tree[rt<<1].pow5+tree[rt<<1|1].pow5)%mod; } void build(int left,int right,int rt) { tree[rt].left=left; tree[rt].right=right; tree[rt].lazy=false; tree[rt].add=0; if(left==right) { scanf("%I64d",&tree[rt].pow0); tree[rt].pow1=(tree[rt].pow0*LMi[left][1])%mod; tree[rt].pow2=(tree[rt].pow0*LMi[left][2])%mod; tree[rt].pow3=(tree[rt].pow0*LMi[left][3])%mod; tree[rt].pow4=(tree[rt].pow0*LMi[left][4])%mod; tree[rt].pow5=(tree[rt].pow0*LMi[left][5])%mod; return; } int mid=(left+right)>>1; build(left,mid,rt<<1); build(mid+1,right,rt<<1|1); pushUp(rt); } void pushDown(int rt); void update(int l,int r,int value,int rt) { if(l==tree[rt].left && tree[rt].right==r) { tree[rt].lazy=true; tree[rt].add=value; tree[rt].pow0=value*(((sum[r][0]-sum[l-1][0])%mod+mod)%mod); tree[rt].pow1=value*(((sum[r][1]-sum[l-1][1])%mod+mod)%mod); tree[rt].pow2=value*(((sum[r][2]-sum[l-1][2])%mod+mod)%mod); tree[rt].pow3=value*(((sum[r][3]-sum[l-1][3])%mod+mod)%mod); tree[rt].pow4=value*(((sum[r][4]-sum[l-1][4])%mod+mod)%mod); tree[rt].pow5=value*(((sum[r][5]-sum[l-1][5])%mod+mod)%mod); return; } pushDown(rt); int mid=(tree[rt].left+tree[rt].right)>>1; if(r<=mid) { update(l,r,value,rt<<1); } else if(l>mid) { update(l,r,value,rt<<1|1); } else { update(l,mid,value,rt<<1); update(mid+1,r,value,rt<<1|1); } pushUp(rt); } void pushDown(int rt) { if(tree[rt].lazy && tree[rt].left!=tree[rt].right) { tree[rt<<1].lazy=tree[rt<<1|1].lazy=true; long long tmp=tree[rt].add; tree[rt<<1].add=tree[rt].add; tree[rt<<1|1].add=tree[rt].add; int mid=(tree[rt].left+tree[rt].right)>>1; //这里可以直接调用update方法对儿子进行更新 update(tree[rt].left,mid,tmp,rt<<1); update(mid+1,tree[rt].right,tmp,rt<<1|1); tree[rt].add=0; tree[rt].lazy=false; } } long long query(int l,int r,int rt,int i) { if(l==tree[rt].left && tree[rt].right==r) { if(i==0) return tree[rt].pow0; else if(i==1) return tree[rt].pow1; else if(i==2) return tree[rt].pow2; else if(i==3) return tree[rt].pow3; else if(i==4) return tree[rt].pow4; else if(i==5) return tree[rt].pow5; } pushDown(rt); int mid=(tree[rt].left+tree[rt].right)>>1; if(r<=mid) { return query(l,r,rt<<1,i)%mod; } else if(l>mid) { return query(l,r,rt<<1|1,i)%mod; } else { return (query(l,mid,rt<<1,i)+query(mid+1,r,rt<<1|1,i))%mod; } } int main() { int x; char ch[5]; scanf("%d%d",&n,&m); init1(); init2(); build(1,n,1); for(int i=1; i<=m; i++) { scanf("%s",ch); if(ch[0]=='=') { scanf("%d%d%d",&L,&R,&x); update(L,R,x,1); } else { scanf("%d%d%d",&L,&R,&k); ans=0; //for(int i=0;i<=k;i++){ for(int i=k; i>=0; i--) { //ans=((ans+((query(L,R,1,i)*C[k][i]%mod)*S[L][k-i]%mod))%mod+mod)%mod; ans=(ans+((query(L,R,1,i)*C[k][i]%mod)*S[L][k-i]%mod))%mod; } printf("%I64d ",ans); } } return 0; }