数学を使用して、差と接頭辞の合計の関係を説明します
違いを学習する前に、プレフィックスの合計の概念と定義を確認する必要があります。プレフィックスと概念を確認するには、ここをクリックしてください。
プレフィックスとコードの実装はわかっています。s[ i ] = s[ i - 1] + a[ i ];
(式1)
つまり、配列Sは配列aの最初のi項目の合計を格納します。これは理解しやすいと思いますが、違いの定義に関しては混乱しやすいです。
なぜ逆の違いがあるのですか。プレフィックス合計の操作?
違いの定義を見てみましょう。違いは、2つの隣接する数値の違いです。
文字通り、その定義に従って直接書くことができます。s[ i ] = a[i] - a[i-1];
(式2)
つまり、配列Sを使用して、配列aの隣接する各番号間の差を記録します。
これらの2つの式を観察し、プレフィックス合計の配列sと配列aを逆にして、式2を取得します。
つまり、数学では、s = a、a = s、次にa [i] = a [i-1] + s [i]とし、反対側にa [i-1]を置いて
s [1]にします。 = a [i] -a [i-1]。プレフィックスの合計と差は一種の逆演算であることがわかります。
次の条件を満たす集合bnを作成します。av
= b1 + b2 + b3 +…+ bv;
配列nがb配列の接頭辞和と呼ばれ、b配列がa配列の差となるようにbnを作成します。
差を使用して、区間和の問題をより適切に解決できます。
配列aが与えられた場合、区間[l、r]の1つに数値cを追加する場合、for(int i = l ;i <= r; i++) a[i] += c;
この時間計算量を初めて使用できます。これはOです。 (n)区間[l、r]が非常に大きい場合、時間外処理が容易であるため、差分演算を使用してs[l] += c; s[r + 1] -= c;
、区間lとrの間にcのみが追加されるようにします。
最後に、cを追加した後、配列aを復元する必要があります。直接「リバース」します。見てみましょう。式2、a [i]を取得する方法、つまりa[i] = s[i] + a[i -1]
例:違い
長さnの整数のシーケンスを入力します。
次に、m個の演算を入力します。各演算には3つの整数l、r、cが含まれます。これは、シーケンス内の[l、r]の間の各数値にcを追加することを意味します。
すべての操作が完了したら、シーケンスを出力してください。
入力形式
最初の行には、2つの整数nとmが含まれています。
2行目には、整数のシーケンスを表すn個の整数が含まれています。
次のm行、各行には、操作を表す3つの整数l、r、cが含まれています。
出力形式は
、最終シーケンスを表すn個の整数を含む1行です。
データ範囲
1≤n、m≤100000、1≤l≤r≤n、
-1000≤c≤1000、
-1000≤
整数列の要素の値≤1000
入力例:
6 3
1 2 2 1 2 1
1 3 1
3 5 1
1 6 1
サンプル出力:
3 4 5 3 4 2
C ++の実装:
#include<iostream>
using namespace std;
const int N = 100010;
int n,m;
int a[N],b[N];
void insert(int l, int r,int c)
{
b[l] += c;
b[r + 1] -=c;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i = 1; i <= n;i ++ ) scanf("%d",&a[i]);
for(int i = 1; i <= n;i ++ ) insert(i, i ,a[i]);
//相当于 for(int i = 1; i <= n; i ++) b[i] = a[i] - a[i-1];
while(m -- )
{
int l, r, c;
scanf("%d%d%d",&l,&r,&c);
insert(l,r,c);
}
//求原数组差分后的情况:
for(int i = 1; i <= n; i ++) b[i] += b[i - 1]; //通过b[i] = b[i] + b[i-1]分解出原数组的a[]的情况
for(int i = 1; i <= n;i ++ ) printf("%d ", b[i]);
//或者 for(int i = 1; i <= n ; i ++) a[i] = b[i]+ a[i-1];
// for(int i = 1; i <= n ; i++) printf("%d ",a[i] );
return 0;
}
微分行列は
、n行m列の整数行列を入力してからq演算を入力します。各演算には、5つの整数x1、y1、x2、y2、cが含まれます。ここで、(x1、y1)および(x2、y2)はサブを表します。行列の左上隅と右下隅の座標。
各操作は、選択した部分行列の各要素の値にcを追加する必要があります。
すべての操作が完了したら、マトリックスを出力してください。
入力形式
最初の行には整数n、m、qが含まれています。
次のn行、各行には、整数の行列を表すm個の整数が含まれます。
次の行qには、各行に5つの整数x1、y1、x2、y2、cが含まれており、操作を表します。
出力形式に
は、n行と各行にm個の整数があり、すべての操作が完了した後の最終的な行列を表します。
データ範囲
1≤n、m≤1000、
1≤q≤100000、
1≤x1≤x2≤n、
1≤y1≤y2≤m、
-1000≤c≤1000、
行列の要素の値-1000≤The ≤1000
入力例:
3 4 3
1 2 2 1
3 2 2 1
1 1 1 1
1 1 2 2 1
1 3 2 3 2
3 1 3 4 1
サンプル出力:
2 3 4 1
4 3 4 1
2 2 2 2
#include<iostream>
using namespace std;
const int N = 1010;
int n, m, q;
int a[N][N], b[N][N];
void insert(int x1, int y1, int x2, int y2, int c)
{
b[x1][y1] += c;
b[x2 + 1][y1] -= c;
b[x1][y2 + 1] -= c;
b[x2 + 1][y2 + 1] += c;
}
int main()
{
scanf("%d%d%d",&n, &m, &q);
for(int i = 1; i <= n; i ++ )
{
for(int j = 1; j <= m; j ++)
scanf("%d",&a[i][j]);
}
for(int i= 1; i <= n ;i ++)
{
for(int j = 1; j <= m ; j ++)
{
insert(i, j, i, j, a[i][j]);
}
}
while(q--)
{
int x1, y1, x2, y2, c;
cin >> x1 >> y1 >> x2 >> y2 >> c;
insert(x1, y1, x2, y2, c);
}
for(int i =1; i <= n; i ++)
{
for(int j = 1; j <= m; j ++)
b[i][j] += b[i - 1][j] + b[i][j -1] - b[i -1][j - 1];
}
for(int i = 1; i <= n; i ++)
{
for(int j = 1; j <= m; j ++)
printf("%d ",b[i][j]);
puts(" ");
}
return 0;
}