题目大意:给你一串数列,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 1000000007 using 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; }