アルゴリズム上級ガイド-基本アルゴリズム-プレフィックスの合計と差

1.レーザー爆弾
問題のリンクの
ここに画像の説明を挿入
解決策:この問題の解決策は、接頭辞と合計に少し似ています。この問題が線分を与えることである場合、線分の各点には対応する値があります。次のことができる爆弾があります。長さnの線分を破壊します。破壊できる最大合計値は、プレフィックス合計で簡単に解決できます。この問題は、1次元のプレフィックス合計を2次元のプレフィックス合計に変換することです。爆発範囲爆弾のは正方形であるため、対角線を知るだけで済みます。最後の2点の位置で三角形を決定できるため、2次元配列f [x] [y]を使用して00点の値を表します。そして、x点とy点によって決定される長方形。次に、この質問も接頭辞と質問に変換されます。問題は、この2次元配列をどのように処理するかです。
次のコードを見てください(f [i] [j]処理前のポイントの値を格納します)

for(int i = 1; i <= 5001; ++ i)
        {
    
    
            for(int j = 1; j <= 5001; ++ j)
            {
    
    
                f[i][j] = f[i][j]+f[i-1][j]+f[i][j-1]-f[i-1][j-1];
            }
        }

その後、この質問は簡単に解決されます

c ++コード:

#include<stdio.h>
#include<iostream>
#include<string.h>
using namespace std;
const int maxn = 5000 + 50;
typedef long long ll;
int f[maxn][maxn];
int main()
{
    
    
    int n, r;
    while(scanf("%d%d", &n, &r) != EOF)
    {
    
    
        if(r == 0)
        {
    
    
            printf("0\n");
            continue;
        }
        int x, y, v;
        memset(f, 0, sizeof(f));
        for(int i = 0; i < n; ++ i)
        {
    
    
            scanf("%d%d%d", &x, &y, &v);
            f[x+1][y+1] = v;
        }
        for(int i = 1; i <= 5001; ++ i)
        {
    
    
            for(int j = 1; j <= 5001; ++ j)
            {
    
    
                f[i][j] = f[i][j]+f[i-1][j]+f[i][j-1]-f[i-1][j-1];
            }
        }
        int ans = 0;
        for(int i = r; i <= 5001; ++ i)
        {
    
    
            for(int j = r; j <= 5001; ++ j)
            {
    
    
                ans = max(ans, f[i][j]-f[i-r][j]-f[i][j-r]+f[i-r][j-r]);
            }
        }
        printf("%d\n", ans);
    }
    return 0;
}

Javaコード:

import java.util.Scanner;

public class Main
{
    
    
	static final int N=5001;
	static int[][] s=new int[N+5][N+5];
	public static void main(String[] args) {
    
    
		Scanner sc=new Scanner(System.in);
		int n=sc.nextInt();
		int r=sc.nextInt();
		for(int i=0;i<n;i++)
		{
    
    
			int x=sc.nextInt();
			int y=sc.nextInt();
			int v=sc.nextInt();
			s[x+1][y+1]=v;
		}
		for(int i=1;i<=N;i++)
		{
    
    
			for(int j=1;j<=N;j++)
			{
    
    
				s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+s[i][j];
			}
		}
		int _max=0;
		for(int i=r;i<=N;i++)
		{
    
    
			for(int j=r;j<=N;j++)
			{
    
    
				if(s[i][j]-s[i-r][j]-s[i][j-r]+s[i-r][j-r]>_max)
					_max=s[i][j]-s[i-r][j]-s[i][j-r]+s[i-r][j-r];
			}
		}
		System.out.println(_max);
		sc.close();
	}
}


2. IncDecシーケンス質問ソリューション
へのリンク
ここに画像の説明を挿入
:まず、この質問の重要なポイントの1つは、区間[l、r]の変更操作です。このトピックの変更操作には機能があります。つまり、+ xや-xではなく、1つだけ加算するか、1つだけ減算します。したがって、高度なデータ構造、線分ツリー、ツリー配列を使用する必要はありません。しかし、違いを使用する必要があります。
各数値が同じであることを確認するにはどうすればよいですか。2つの隣接する数値の差が0であることを確認するだけで済みます。2つの隣接する数値すべての差を配列b [n]、b [n] = aに格納するとします。 [n] -a [n-1];したがって、現時点では、b [n]の配列を0に変換する方法を見つけようとしています。b[nのペアを1つ加算または減算した場合の効果を見てみましょう。 ]をタイトルの間隔に追加します。[a、b]セグメントの数に1を追加し、次にb [b]から1を引いた数に1を追加します。b配列をできるだけ早く0にするために、貪欲なアイデアでは、b配列の正と負のペアに加えて、正の数から1つの負の1を引いたものを作成します。正または負の数が多い場合は、b [1]が0であるかどうかにかかわらず、b [1]とします。
C ++コードには影響しません

#include <bits/stdc++.h>

using namespace std;

int main() {
    
    
  vector<int> d;
  d.push_back(0);
  int n, x, y;
  cin >> n;
  cin >> x;
  for (int i = 1; i < n; i++) {
    
    
    cin >> y;
    d.push_back(y - x);
    x = y;
  }
  long long pos = 0, neg = 0;
  for (auto x : d) {
    
    
    if (x > 0) pos += x;
    else neg -= x;
  }
  cout << min(pos, neg) + abs(pos - neg) << endl;
  cout << abs(pos - neg) + 1;
  return 0;
}

Javaコード:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Scanner;

public class Main {
    
    
    static final int N=100000+10;
    public static void main(String[] args) {
    
    
        Scanner sc=new Scanner(System.in);
        int n;
        long a[]=new long [N];
        n= sc.nextInt();
        for(int i=1;i<=n;i++)
            a[i]=sc.nextInt();
        long q,p;
        q=0;
        p=0;
        for(int i=n;i>=2;i--)
        {
    
    
            long x=a[i]-a[i-1];
            if(x>0)
                q+=x;
            else
                p-=x;

        }
        System.out.println(Math.max(q,p));
        System.out.println(Math.abs(q-p)+1);


    }




}

3.最も高い牛の
問題リンク
ここに画像の説明を挿入
ソリューション:各牛を最も高い高さにするために、最初の牛と最後の牛が問題によって与えられた最も高い高さを持つことができ、次に残りの牛は差の関係に従って取得できます。aとbがお互いを見ることができると仮定すると、aとbの間の牛がabよりも短いことを意味し、cha [a + 1] -1 cha [b] +1;
c ++コード:

#include <iostream>
#include <cstdio>
#include <cmath>
 
using namespace std;
 
int N, P, H, M;
int a[10005];
bool appear[10005][10005];
 
int main()
{
    
    
    cin >> N >> P >> H >> M;
    a[1] = H;
    for (int i = 1, A, B; i <= M; i ++ )
    {
    
    
        cin >> A >> B;
        if(A > B) swap(A, B);
        if(!appear[A][B])
        {
    
    
            appear[A][B] = 1;
            a[A + 1] --, a[B] ++;
        }
    }
 
    for (int i = 1; i <= N; i ++ )
        a[i] += a[i - 1], cout << a[i] << endl;
    return 0;
}


Javaコード:

import java.util.*;
public class Main {
    
    

    public static void main(String[] args) {
    
    
        Scanner cin = new Scanner(System.in);
        int n = cin.nextInt();
        int[] arr = new int[n + 1];
        int p = cin.nextInt();
        int h = cin.nextInt();
        Arrays.fill(arr, h);
        int m = cin.nextInt();
        Set<String> set = new HashSet<String>();
        int[] op = new int[2];
        for (int i = 0; i < m; i++) {
    
    
            op[0] = cin.nextInt(); // A
            op[1] = cin.nextInt(); // B
            Arrays.sort(op);
            if (!set.contains(op[0] + "" + op[1])) {
    
    
                set.add(op[0] + "" + op[1]);
                for (int c = op[0] + 1; c < op[1]; c++)
                    arr[c]--;
            }
        }
        for (int i = 1; i <= n; i++)
            System.out.println(arr[i]);
    }
}


おすすめ

転載: blog.csdn.net/jahup/article/details/108361206