目次
プレフィックスの合計とは何ですか?
プレフィックス合計の1次元の場合
元の配列a []とプレフィックスおよび配列S []の2つの配列を定義します。
元の配列:a1、a2、a3 ... an
S1 = a1、S2 = a1 + a2、S3 = a1 + a2 + a3と言います
ルールを見つけるのは難しくありません。プレフィックスの合計は、Si = a1 + a2 +……+ ai; Si = Si-1 + ai;として取得できます。
次に、2つの問題があります。
1.Siを見つける方法
2.接頭辞とSiは何に使用され、それらの機能は何ですか?
S0 = 0を定義します
コード実装プレフィックスの合計は次のとおりです。
for (int i = 1; i <= n; i++)
{
s[i] = s[i - 1] + a[i];
}
次に、少し展開して、区間[l、r]の合計を見つけましょう(lは左を表し、rは右を表します)
この場合、この段落の合計は次のようになります。Sr-Sl-1
図に示すように、このメソッドは時間計算量をO(1)に減らすことができます。
質問を見てみましょう:
長さnの整数のシーケンスを入力します。
次に、m個のクエリを入力し、クエリごとにl、rのペアを入力します。
クエリごとに、元のシーケンスのl番目の数値からr番目の数値までの合計を出力します。
入力フォーマット
最初の行には、2つの整数nとmが含まれています。
2行目には、整数のシーケンスを表すn個の整数が含まれています。
次のm行、各行には、クエリ間隔の範囲を表す2つの整数lとrが含まれています。
出力フォーマット
合計m行あり、各行は1つのクエリ結果を出力します。
データ範囲
1≤l≤r≤n1≤n
、m≤100000-1000≤シーケンス
内の要素の値≤1000入力サンプル:
5 3 2 1 3 6 4 1 2 1 3 2 4
サンプル出力:
3 6 10
コードは次のように実装されています。
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
int a[N], s[N];
int n, m;
int main()
{
s[0] = 0;
cin >> n >> m;
for (int i = 1; i <= n; i++)
{
scanf("%d", &a[i]);
}
for (int i = 1; i <= n; i++)
{
s[i] = s[i - 1] + a[i];//前缀和公式
}
while (m--)
{
int l, r;
cin >> l >> r;
printf("%d\n", s[r] - s[l - 1]);//区间和公式
}
return 0;
}
プレフィックス合計の2次元の場合
//二维前缀和
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
s[i][j] = s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1] + a[i][j];
}
}
トピックを見てみましょう:
n行m列の整数行列を入力してからqクエリを入力します。各クエリには、サブ行列の左上隅と右下隅の座標を表す4つの整数x1、y1、x2、y2が含まれています。
クエリごとに、サブマトリックス内のすべての数値の合計が出力されます。
入力フォーマット
最初の行には、3つの整数n、m、qが含まれています
次のn行、各行にはm個の整数が含まれ、整数の行列を表します。
次のq行では、各行に一連のクエリを表す4つの整数x1、y1、x2、y2が含まれています。
出力フォーマット
全部でq行あり、各行はクエリ結果を出力します。
データ範囲
1≤n、m≤10001≤q≤2000001≤x1≤x2≤n1≤y1≤y2≤m
-
1000≤
行列
内の要素の値≤1000入力サンプル:
3 4 3 1 7 2 4 3 6 2 8 2 1 2 3 1 1 2 2 2 1 3 4 1 3 3 4
サンプル出力:
17 27 21
コードは次のように実装されています。
#include <bits/stdc++.h>
using namespace std;
const int N = 1010;
int a[N][N], s[N][N];
int n, m;
int q;
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++)
{
s[i][j] = s[i][j - 1] + s[i - 1][j] - s[i - 1][j - 1] + a[i][j];
}
}
while (q--)
{
int x1, y1, x2, y2;
scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
printf("%d\n", s[x2][y2] - s[x2][y1 - 1] - s[x1 - 1][y2] + s[x1 - 1][y1 - 1]);
}
return 0;
}
一次元の違いの場合
質問を見てみましょう:
長さnの整数のシーケンスを入力します。
次に、m個の演算を入力します。各演算には3つの整数l、r、cが含まれます。これは、シーケンス内の[l、r]の間の各数値にcを追加することを意味します。
すべての操作が完了したら、シーケンスを出力してください。
入力フォーマット
最初の行には、2つの整数nとmが含まれています。
2行目には、整数のシーケンスを表すn個の整数が含まれています。
次のm行では、各行に操作を表す3つの整数l、r、cが含まれています。
出力フォーマット
n個の整数を含む行は、最終シーケンスを表します。
データ範囲
1≤n、m≤1000001≤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
区間[l、r]のすべての数にcを追加する方法を考えてください。
できるよ:
区間[l、r]をq個の部分区間に分割します
区間[l、l] a [l] + c区間[l + 1、l + 1] a [l + 1] + c……領域[r、r] a [r] + c ;;
完全なコードは次のとおりです。
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
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]);
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];
for (int i = 1; i <= n; i++)
{
printf("%d ", b[i]);
}
return 0;
}
違いの2次元の場合
一次元の状況は、間隔に値を追加することです
2次元の場合、部分行列に値を追加します
質問を見てみましょう:
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≤valuematrix≤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 <bits/stdc++.h>
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;
scanf("%d%d%d%d%d", &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]);
}
printf("\n");
}
return 0;
}