プログラム設計の考え方と実践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;
}