前缀和

一维前缀和

  • 作用:快速查询数组a[l]~a[r]的和,时间复杂度为o(1)。
  • 求法:例如数组a[],用一个数组sum[]来记录它的前n项和,例如sum[n]表示a[1]+a[2]+...+a[n]。
  •  1 int sum[1000];
     2 void init()
     3 {
     4     for(int i=1; i<=n; i++)
     5         sum[i]=sum[i-1]+a[i];
     6 }
     7 int query(int l, int r)
     8 {
     9     return sum[r]-sum[l-1]; 
    10 }

加一道前缀和的骚题。。。

这道题居然可以用前缀和来解决,没想到。。。

我们可以枚举自然数段的长度为i

当i为2时,有 12 23 45 67

为i3时有123 234 345 456

为i4时有1234 2345 3456 4567

我们可以发现这些串就可以表示任意一段的区间的和了, 然后奇妙的事发生了, 当要表示长度为i的区间的和时只需要用到第一列的数据和,然后在它的基础上加上k倍的i即可表示

即设前缀和为a[n], 设要表示的数据和为n,如果存在一个区间和能表示这个数, 那么对应存在一个k满足n=sum[i]+k*i;然后上代码。

 1 #include<cstdio>
 2 long long a[2000005];
 3 int main()
 4 {
 5     int n;
 6     scanf("%d", &n);
 7     for(int i=1; i<=2000000; i++)
 8     {
 9         a[i]=a[i-1]+i;
10     }
11     for(int i=2000000; i>=2; i--)
12     {
13         if(n>=a[i] && (n-a[i])%i==0)
14         {
15             printf("%d %d\n", 1+(n-a[i])/i, (n-a[i])/i+i);
16         }
17     }
18 }

 

二维前缀和

  • 作用:快速查询数组a[][]任意二维区间的和
  • 求法:用一个数组sum[n][m]表示所有a[n'][m']的和(1<=n'<=n,1<=m'<=m)。
  • 下面代码的例图。
  •  1 int sum[1000][1000];
     2 void init()
     3 {
     4     for(int i=1; i<=n; i++)
     5         for(int j=1; j<=m; j++)
     6             sum[i][j]=sum[i][j-1]+sum[i-1][j]-sum[i-1][j-1]+a[i][j];
     7 }
     8 int query(int x1, int y1, int x2, int y2)
     9 {
    10     return sum[x2][y2]-sum[x2][y1-1]-sum[x1-1][y2]+sum[x1-1][y1-1];
    11 }

     

 一维差分

  • 作用:设数组为a[],对多次a数组上的区间[l,r]实现加减val的操作(将对区间的的操作转化为对两个端点的操作)。
  • 做法:
     1 int a[n];
     2 int d[n];
     3 int c[n];
     4 void init(int l, int r, int val)
     5 {
     6     d[l]+=val;d[r+1]-=val;
     7 }
     8 for(int    i=1; i<=n; i++)
     9 {
    10     c[i]=c[i-1]+d[i];
    11 }
    12 for(int i=1; i<=n; i++)
    13 {
    14     a[i]+=c[i];
    15 }

二维差分

  •  1 void init(int x1, int y1, int x2, int y2, int val)
     2 {
     3     sum[x1][y1] += val;
     4     sum[x1][y2 + 1] -= val;
     5     sum[x2 + 1][y1] -= val;
     6     sum[x2 + 1][y2 + 1] += val;
     7 }
     8 
     9 void get()
    10 {
    11     for(int i = 1; i <= n; i++)
    12         for(int j = 1; j <= n; j++)
    13             sum[i][j] += sum[i][j-1] + sum[i-1][j] - sum[i-1][j-1];
    14 }

     

 

posted @ 2018-07-26 13:31  paranoid。  阅读(134)  评论(0编辑  收藏  举报