您的位置:首页 > 产品设计 > UI/UE

CodeForces 266E - More Queries to Array 拆解求和公式,线段树区间更新与求和

2013-07-23 10:09 417 查看
题意很裸...但做起来大有文章...

区间成段更新并求和..第一想到的应该是线段树...但是题目给的区间求和是

无法直接下手

之所以不好直接下手..是因为不能成段的更新和统计和..由于k<=5...可以把右边的括号展开...

只看右边括号..... k=0 : (i-l+1)^0 = 1

k=1 : (i-l+1)^1 = i + ( 1-l )

k=2 : (i-l+1)^2 = i^2 + 2*(1-l) + (1-l)^2

............

把 (i-l+1)^k 看成 (i+ (1-l))^k...就可以很方便的进行二项式展开...k=x , (i+(1-l))^x =sigma(C(K,i)*i^x*(1-l)^(x-i)) ( 0<=i<=k )

而如此可以得到要求的和为 = A*Sigma(ai) + B*Sigma(ai*i) + C*Sigmal(ai*i^2)....( l<=i<=r , A,B,C..为常数)

k至多为5...那么0,1,2,3,4,5...构造六颗线段树..分别代表ai , ai*i , ai*i*i , ai*i*i*i , ai*i*i*i*i , ai*i*i*i*i*i

做了一些预处理后....这六颗树都可以很方便的成段更新和统计...

可以事先将1+1+1+1+1+.....1+2+3+4+5.... ; 1+4+9+16+25.... ; 1+8+27+64+125....这类表打出来

比如说要更新 3 5 段 为 3

那么 sum[0](3~5) = (5 - 2)*3 = 9

sum[1](3~5) = (25 - 3)*3 = 72

sum[2](3~5) = (55 - 5)*3 = 150

,,,,,,,,,,,,,,

当要询问区间时...用这六棵线段树算出这个区间的ai , ai*i , ai*i*i , ai*i*i*i , ai*i*i*i*i , ai*i*i*i*i*i..再用二项式的方法得出答案就好了...

由于一些去摸运算..注意时时刻刻取摸..并且当计算出负数时要加回正数( (a-b)%c 是大于0的 但(a%c - b%c)可能会小于0,,改回正数..也就是结果+MOD)

Program:

#include<iostream>
#include<stack>
#include<queue>
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<cmath>
#define ll long long
#define oo 1000000007
#define MAXN 100005
using namespace std;
struct node
{
      ll a[6]; 
};
ll sum[6][MAXN<<2],col[MAXN<<2],data[6][MAXN],C[6][6],POW[MAXN][6];  
node ADD(node a,node b)
{
      int i;
      for (i=0;i<6;i++) a.a[i]=(a.a[i]+b.a[i])%oo;
      return a;
}
void PreWork()
{
      int i,j;
      ll x;
      memset(data,0,sizeof(data));
      POW[0][0]=1;
      for (i=1;i<=100000;i++)
      {
             x=1;
             for (j=0;j<6;j++) POW[i][j]=x,data[j][i]=(data[j][i-1]+x)%oo,x=(x*i)%oo; 
      }
      for (i=0;i<6;i++) C[i][0]=C[i][i]=1;
      for (i=1;i<6;i++)
         for (j=1;j<6;j++)
           C[i][j]=C[i-1][j-1]+C[i-1][j];
      return ;
}
void PushDown(int l,int r,int now)
{
      int i,mid=(l+r)/2;
      ll x;
      if (col[now]<0) return;
      col[now<<1]=col[(now<<1)|1]=col[now];
      for (i=0;i<6;i++) 
      {  
              x=data[i][mid]-data[i][l-1];
              if (x<0) x=oo+x;
              sum[i][now<<1]=(col[now]*x)%oo;
              x=data[i][r]-data[i][mid];
              if (x<0) x=oo+x;
              sum[i][(now<<1)|1]=(col[now]*(data[i][r]-data[i][mid]))%oo;
      }
      col[now]=-1; 
      return;
}
void update(int L,int R,int c,int l,int r,int now)
{
      int i;
      ll x;
      if (L<=l && R>=r)
      {
             col[now]=c;      
             for (i=0;i<6;i++) 
             {
                    x=data[i][r]-data[i][l-1];
                    if (x<0) x=oo+x;
                    sum[i][now]=(c*x)%oo;
             }
             return;
      }
      PushDown(l,r,now);
      int mid=(l+r)>>1; 
      if (L<=mid) update(L,R,c,l,mid,now<<1);
      if (mid<R)  update(L,R,c,mid+1,r,(now<<1)|1);
      for (i=0;i<6;i++) sum[i][now]=(sum[i][now<<1]+sum[i][(now<<1)|1])%oo;
      return;
}
node query(int L,int R,int l,int r,int now)
{
      node h,p;
      if (L<=l && R>=r)
      {
             for (int i=0;i<6;i++) h.a[i]=sum[i][now];
             return h;
      }
      PushDown(l,r,now);
      int mid=(l+r)>>1;
      memset(h.a,0,sizeof(h.a));
      if (L<=mid) h=ADD(h,query(L,R,l,mid,now<<1));
      if (mid<R)  h=ADD(h,query(L,R,mid+1,r,(now<<1)|1));      
      return h;
}
ll getans(node h,ll L,int k)
{
      int i;
      ll t,ans=0;
      for (i=0;i<=k;i++)
      {
             t=(C[k][i]*h.a[i])%oo;
             t=(t*POW[L-1][k-i])%oo;
             if ((k-i)%2) t=-t;
             ans=(ans+t)%oo;
      }
      return (ans+oo)%oo;
}
int main()
{ 
      int i,n,m,x,y,z;
      char c;  
      PreWork();
      while (~scanf("%d%d",&n,&m))
      {
              memset(sum,0,sizeof(sum));
              memset(col,-1,sizeof(col));
              for (i=1;i<=n;i++)
              {
                     scanf("%d",&x);
                     update(i,i,x,1,n,1);
              }
              while (m--)
              {
                     do { c=getchar(); } while(c!='=' && c!='?');
                     scanf("%d%d%d",&x,&y,&z);
                     if (c=='?')  printf("%I64d\n",getans(query(x,y,1,n,1),x,z));               
                        else update(x,y,z,1,n,1);
              }
      }
      return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: