アルゴリズムのプレフィックス合計と差分コードの実装とアルゴリズム思考分析

目次

プレフィックス合計の1次元の場合

プレフィックス合計の2次元の場合

一次元の違いの場合

違いの2次元の場合


プレフィックスの合計とは何ですか?

プレフィックス合計の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;
}

 

おすすめ

転載: blog.csdn.net/JixTlhh/article/details/115254947