題目大意:給你一串數列,a[1]~a[n]。有兩種操作
操作1:", (1 ≤ l ≤ r ≤ n; 0 ≤ x ≤ 109).
表示將區間[l,r]中的數全賦值為x。
操作2:"", (1 ≤ l ≤ r ≤ n; 0 ≤ k ≤ 5).
表示計算的值,模數1000000007後輸出。
先給你q個操作,對於每一個操作2,輸出對應的值。
思路:這道題的關鍵就在k的範圍很小,只有0到5,所以可以考慮建6可線段樹分別討論。對於特定的k,怎麼求要求計算的值呢?在做過幾次嘗試後,我發現很難直接求得(對於不同的 l r,所乘的係數也不同)。既然直接求難度大,那我們不妨分開來求,將所要求的式子拆開來看看。
對於k=0,則相當於求區間和。
對於k=1,原式可化為 a[i]+(1-l);
對於k=2,原式可化為 a[i]^2-2*(l-1)*a[i]+(l-1)^2;
對於k=3,原式可化為 a[i]^3-3*(l-1)*a[i]^2+3*(l-1)^2*a[i]-(l-1)^3;
。。。。。。
我們可以發現對於每個a[i]項,它所乘的係數變得可以確定了(每一個都和(l-1)有關,滿足二項式定理)。如果我們線上段樹中,對於每一個個區間我們維護,那麼對於每一個不同的K(k很小),我們都可以根據上面的式子,展開來分別求,事情到了這一步演算法已經基本成型了,剩下的就是實現了。我們首先要建立6個線段樹來維護,因為資料量大,所以我們首先將(i^j)%1000000007的值預先處理一下,用到的時候在調用即可。對於操作1,我們如果把一個區間的數全賦值為x,則該區間的和則為x*(l^j+(l+1)^j+....(r)^j),對於括弧裡的值也可以通過預先處理來實現,最後注意由於所求的值相當的大,在一些中間運算中可能會爆
long long的,所以一定要在每一個可能越界的地方模數。最後看實現。
#include <iostream>#include <string.h>#include <stdio.h>#include <algorithm>#define maxn 100010#define mod 1000000007using namespace std;#define mid ((t[p].l+t[p].r)>>1)#define ls (p<<1)#define rs (ls|1)long long pow[maxn][6],num[maxn][6];long long a[maxn];void init(){ long long i; memset(num,0,sizeof(num)); memset(pow,0,sizeof(pow)); for(i=0;i<=100000;i++) { int j; for(j=0;j<6;j++) { int k=j; long long tmp=1; while(k--) tmp=(tmp*i)%mod; pow[i][j]=tmp; if(i!=0) num[i][j]=(num[i-1][j]+tmp)%mod; } }}struct tree{ int l,r; int lazy; long long sum[6];}t[maxn<<2];void pushup(int p){ int i; for(i=0;i<6;i++) t[p].sum[i]=(t[ls].sum[i]+t[rs].sum[i])%mod;}void update(int p,int val){ t[p].lazy=val; int i,l=t[p].l,r=t[p].r; for(i=0;i<6;i++) t[p].sum[i]=((val*(num[r][i]-num[l-1][i]))%mod+mod)%mod;}void pushdown(int p){ if(t[p].lazy!=-1) { update(ls,t[p].lazy); update(rs,t[p].lazy); t[p].lazy=-1; }}void build(int p,int l,int r){ t[p].l=l,t[p].r=r,t[p].lazy=-1; if(l==r) { int i; for(i=0;i<6;i++) { t[p].sum[i]=(pow[l][i]*a[l])%mod; } return; } build(ls,l,mid); build(rs,mid+1,r); pushup(p);}void add(int p,int l,int r,int val){ if(t[p].l==l&&t[p].r==r) { update(p,val); return; } pushdown(p); if(l>mid) add(rs,l,r,val); else if(r<=mid) add(ls,l,r,val); else { add(ls,l,mid,val); add(rs,mid+1,r,val); } pushup(p);}long long query(int p,int l,int r,int k){ if(t[p].l==l&&t[p].r==r) { return t[p].sum[k]; } pushdown(p); if(l>mid) return query(rs,l,r,k); else if(r<=mid) return query(ls,l,r,k); else { return (query(ls,l,mid,k)+query(rs,mid+1,r,k))%mod; }}int l,r;long long g(int a,int b,int c){ return (query(1,l,r,c)*((a*pow[l-1][b])%mod))%mod;}int main(){ init(); int n,q,i; scanf("%d%d",&n,&q); for(i=1;i<=n;i++) scanf("%I64d",&a[i]); build(1,1,n); char str[2]; int x; while(q--) { scanf("%s%d%d%d",str,&l,&r,&x); if(str[0]=='=') { add(1,l,r,x); } else { long long tmp=0; if(x==0) { tmp=query(1,l,r,0); } else if(x==1) { tmp=((g(1,0,1)-g(1,1,0))%mod+mod)%mod; } else if(x==2) { tmp=((g(1,0,2)-g(2,1,1)+g(1,2,0))%mod+mod)%mod; } else if(x==3) { tmp=((g(1,0,3)-g(3,1,2)+g(3,2,1)-g(1,3,0))%mod+mod)%mod; } else if(x==4) { tmp=((g(1,0,4)-g(4,1,3)+g(6,2,2)-g(4,3,1)+g(1,4,0))%mod+mod)%mod; } else if(x==5) { tmp=((g(1,0,5)-g(5,1,4)+g(10,2,3)-g(10,3,2)+g(5,4,1)-g(1,5,0))%mod+mod)%mod; } printf("%I64d\n",tmp); } } return 0;}