プログラム設計の考え方と実践Week5操作(3/4 /データクラス)

プログラム設計の考え方と実践Week5操作(3/4 /データクラス)

- 最大の長方形

ヒストグラムに、ヒストグラムで最大の矩形領域を見つけます。例えば、左からヒストグラムにおける次の像高右それらが広い2、1、4、5、1、3、3、1であり、最大の矩形が遮光されます。

入力

データの複数のセットを含む入力。データの各セットは、整数nによって小さな長方形のヒストグラム表現され、あなたがとることができる、1 <= N <= 100000次いで整数h1を次のn、...、HN、満足0 <=がhi <= 1000000000小さな四角形のそれぞれの左から右へ、これらの数字は、ヒストグラムの高さを表し、各小矩形の幅は1です。終了時に0に試験データ。

出力

ライン毎にテストデータ出力は、整数回答を表します。

Sample Input
7 2 1 4 5 1 3 3
4 1000 1000 1000 1000
0
Sample Output
8
4000

分析

各矩形は、その位置(番号)であり、そのうちの一つ2つのパラメータを有し、第二は、その高さです。各矩形の、左右のより隣接する矩形の高さより高いことを条件として、「拡張」または自体を等しくすることができます。このように、我々は、左端と右端の範囲を決定した後、最後の比較矩形の最大の矩形領域を見つけることができます。

単調スタックアップの詳細な説明。最も遠い届く右の例では、各長方形。スタックを設定し、スタックが空でない場合は、その最初から長方形を横断し、四角形の位置のスタック高さの最上部には、スタックは常に正しい拡張アプリケーションへの要素の中で最も遠いされ、その結果、長方形の現在の高さは、ポップアップよりも大きくなります。

#include <iostream>
#include <stack>
using namespace std;
int h[100010];
int l[100010];
int r[100010];
int n;
long long ans=0;
int main() {
    while (cin>>n&&n!=0) {
        ans=0;
        for (int i=1; i<=n; i++) {
            cin>>h[i];
            l[i]=0;
            r[i]=n+1;
        }
        stack<pair<int, int> > s;
        for (int i=1; i<=n; i++) {
            while (!s.empty()&&s.top().second>h[i]) {
                r[s.top().first]=i;
                s.pop();
            }
            s.push(pair<int, int>(i,h[i]));
        }
        stack<pair<int, int> > s2;
        for (int i=n; i>=1; i--) {
            while (!s.empty()&&s.top().second>h[i]) {
                l[s.top().first]=i;
                s.pop();
            }
            s.push(pair<int, int>(i,h[i]));
        }
        for (int i=1;i<=n; i++) {
            if((long long)(r[i]-l[i]-1)*h[i]>ans)
            ans=(long long)(r[i]-l[i]-1)*h[i];
        }
        cout<<ans<<endl;
    }
    return 0;
}

B - TTの魔法猫

みんなの助け先週のおかげで、TTは、最終的にはかわいい猫を得ました。しかし、どのようなTTは期待していなかったが、これは魔法の猫であるということです

。ある日、魔法猫は彼に問題を与えることによって、TTの能力を調査することを決めました。それは、世界地図から選ぶN都市で、[i]はi番目の市が所有する資産価値を表しています。

そして、魔法の猫は、いくつかの操作を実行します。各ターンは、区間[L、R]内の都市を選択し、cでそれらの資産価値を増大させることです。そして最後に、q個の作業の後、各都市の資産価値を与えるために必要とされます。

あなたは、TTは、答えを見つけるのを助けることができますか?

入力は、

都市や操作の数-最初の行は二つの整数N、Q(1≤n、q≤2⋅105)を含みます。

2行目は、配列Aの要素を含む:整数は、A2、...、(-106≤ai≤106)A1。

次いで、Qラインは、各ラインが操作を表し、従います。i番目の行は、i番目の操作のための3つの整数L、R及びC(1≤l≤r≤n、-105≤c≤105)を含みます。

出力

を印刷nは整数A1、A2、...、1行に1つずつ、およびaiはi番目の都市の最終資産価値に等しくなければなりません。

Input
4 2
-3 6 8 4
4 4 -2
3 3 1
Output
-3 6 9 2
Input
2 1
5 -2
1 2 4
Output
9 2
Input
1 2
0
1 1 -8
1 1 -6
Output
-14

分析

タイトルの平均は、すべての都市の資産を与え、複数の操作の後、各都市の資産は、価値の変動の範囲を持っているので、こと、市の資産のすべてを与え

、時間のかかる受け入れられないだろう、各都市による場合。微分法、ディファレンシャル新しいアレイを使用して、マッピング関係は、Bである[1] = A [1]、B [N-] = A [N-] -a N--。1資産の範囲内で変更X [LT L、R&]は、に、差異の必要性は、L番目の配列x、R + 1番目の第1変化-x変更します。最後に、利用可能な方法は、資産の累積合計は、各都市の変化の後に得られました。

#include<stdio.h>
typedef long long ll;
ll a[200005];
ll b[200005];
int main()
{	
	
	ll l,r,n,q,c;
	scanf("%lld %lld",&n,&q);
	for(ll i =1 ; i<=n ;i++){
		scanf("%lld",&a[i]);
	}
	for(ll i=1; i<=n; i++){
		b[i]=a[i]-a[i-1];
	}
	for (ll i=1; i <= q; i++)
	{
		scanf("%lld %lld %lld",&l,&r,&c);
		b[l] +=c;
		b[r+1] -= c;
	}
	printf("%lld",b[1]);
    long long sum = b[1];
	for(ll i=2;i<=n;i++)	
	{
		sum +=b[i];
		printf(" %lld",sum);
	}
	printf("\n");
	return 0;
}

C - 文字列のバランス

唯一の「Q」、「W」、含ま長N S個の列、 「E」、「R」 文字の4種類。N / 4の数の両方が、それは文字の4種類の文字列でバランスが取れている場合、文字列に表示されます。

Sは現在、同じ長さのサブストリングの連続期間とすることができますので、それはバランスの取れた文字列になること、あるいは?ストリングの最小の長さを求めて、唯一の4文字を含む任意の文字列を置き換える
sが0を出力をバランスしている場合を。

入力

行は、与えられた文字列sを表し、

出力

答えを表しアン整数

Input
QWER
Output
0
Input
QQWE
Output
1
Input
QQQW
Output
2
Input
QQQQ
Output
3



1 <= N - 、文字列のみ'Q'を含む<^ = 10 5、N-複数4で、 'W'、 'E' 及びR ''。

分析

これは、定規、エミュレート対象です。


まず、各文字の統計情報の数は、条件が満たされているかどうかを判断します。

不均衡であれば、一定の範囲内の要素を変更することにより、文字列全体は、バランスを達成するための最小間隔を決定するように、可動部の手段によって。コードにはコメントがあります。

#include<bits/stdc++.h>
using namespace std;
int main() {
    string s;
    cin >> s;
    vector<char> chars;//{'Q','W','E','R'};
    chars.push_back('Q');//为四个字符编号,便于统计数目
    chars.push_back('W');
    chars.push_back('E');
    chars.push_back('R');
    map<char, int> cnt;
    bool balance = true;
    for (auto ch : s)//统计每个字符出现的次数
        ++cnt[ch];
    int len = s.size();
    int n = len / 4;
    for (auto ch : chars)
    {
        cnt[ch] -= n;
        if (cnt[ch] > 0)
            balance = false;
    }
    if (balance == true) {
        cout << 0 << endl;
        return 0;
    }
        
    int left = 0, right = 0, num = len;
    while (left <= right && right < len)
    {
        bool find = true;
        --cnt[s[right]];//假设所选区间最右边的元素被替换
        while (find)
        {
            for (auto ch : chars)//遍历字符串
            {
                if (cnt[ch] > 0)//尚且不平衡
                {
                    find = false;//中断循环
                    break;
                }
            }
            if (find == true)//如果通过改变区间最右边元素平衡
            {
                num = min(num, right - left + 1);
                ++cnt[s[left++]];//左端点向右移动
            }
        }
        ++right;//右端点向右移动
    }
    cout << num << endl;
    return 0;
}

D - スライディングウィンドウスライディングウィンドウ

ZJMは、それぞれ、最大値と最小値毎に列数と窓kのサイズNの長さを有し、ウィンドウは列に前後に移動させることができる。ZJMは現在スライディングウィンドウ内で左から右に知りたい、窓何例:
列の数は、kは3に等しく、[13-1-35367]、です。

Window position	                Minimum value   Maximum value
[1  3  -1] -3  5  3  6  7 	    -1	            3
 1 [3  -1  -3] 5  3  6  7 	    -3	            3
 1  3 [-1  -3  5] 3  6  7 	    -3	            5
 1  3  -1 [-3  5  3] 6  7 	    -3	            5
 1  3  -1  -3 [5  3  6] 7 	    3	            6
 1  3  -1  -3  5 [3  6  7]	    3	            7

入力は、

2つの行を入力します。二つの整数nとkの最初の行はサイズおよびスライディングウィンドウシリーズ、1 <= K <= Nの長さ <= 1000000。第二行は、n ZJMの列の整数を表しています。

出力

出力2つの系統。左から右へ、各スライディングウィンドウ位置の第1の出力ライン、スライディングウィンドウ内の最小値。2行目は最大です。

Sample Input
8 3
1 3 -1 -3 5 3 6 7
Sample Output
-1 -3 -3 -3 3 3
3 3 5 5 6 7

分析

アナログの配列と両端キュー。キューが空でない場合、必要最小限のウィンドウの場合には、現在の要素数の全ては、最小の要素が現在のウィンドウに格納されているように、より大きい又は空気のチームに排出等しいです。キューの先頭の各検査は、有効期限が切れポップアップ表示の有効期限が切れていない

別の状況を同じように議論を。とき、同じ番号の数が間違っていると、避難所に等しい場合は、)、しかし、まだそれはタイムアウトしません、ノート、pop_back(に一つのことをSTLを使用することができます。

#include<stdio.h>
int arr[1000005];
int dq[1000005];
int ans1[1000005];
int ans2[1000005];
int main()
{
    int n,k;
    scanf("%d%d",&n,&k);
    for(int i=0;i<n;++i){
    	scanf("%d",&arr[i]);
	}
	int l=0,r=-1;
	for(int i=0;i<n;++i)
	{
		while(r>=l&&arr[dq[r]]>=arr[i])//不空,则从尾到头,弹出所有比当前元素大的 
		{
			r--;
		}
		dq[++r]=i;//当前元素序号入队 
		if(i>=k-1&&i-dq[l]>=k) //队首过期 
		{
			l++;
		}
		ans1[i]=arr[dq[l]];
	}
	l=0,r=-1;
	for(int i=0;i<n;++i)
	{
		while(r>=l&&arr[dq[r]]<=arr[i])
		{
			r--;
		}
		dq[++r]=i;
		if(i>=k-1&&i-dq[l]>=k)
		{
			l++;
		}
		ans2[i]=arr[dq[l]];
	}
	printf("%d",ans1[k-1]);
	for(int i=k;i<n;++i){
		printf(" %d",ans1[i]);
	}
	printf("\n%d",ans2[k-1]);
	for(int i=k;i<n;++i){
		printf(" %d",ans2[i]);
	}
	printf("\n");
    return 0;
}

おすすめ

転載: www.cnblogs.com/master-cn/p/12635508.html