欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Week5 W(A - 最大矩形)(B - TT's Magic Cat)(C - 平衡字符串)(D - 滑动窗口)

程序员文章站 2022-07-12 15:17:15
...

A-最大矩形

题意

Week5 W(A - 最大矩形)(B - TT's Magic Cat)(C - 平衡字符串)(D - 滑动窗口)Week5 W(A - 最大矩形)(B - TT's Magic Cat)(C - 平衡字符串)(D - 滑动窗口)

思路

维护一个递增单调栈,从左到右遍历矩形,空栈或者矩形高大于栈顶矩形的高,入栈,否则计算栈内矩形各自的最大面积(设当前栈顶的高为最高的高度)

代码

#include<iostream>
#include<stack>
#define llong long long
#define For(i,a,n) for(register int i=a;i<=n;i++)
using namespace std;

const int maxn = 100005;

int n, cnt;
llong a[maxn];
llong s[maxn];
llong ans;

int main(){
	ios::sync_with_stdio(0);
    while(cin>>n){
    	if(n==0) break;
	    For(i,1,n) cin>>a[i];
	    ans = 0; cnt = 0;
	    For(i,1,n+1){
	    	a[n+1] = 0;
	    	if(!cnt || a[i]>a[s[cnt]]){
	    		s[++cnt] = i;
	    	}
	    	else{
	    		while(cnt && a[i]<=a[s[cnt]]){
	    			int t = s[cnt--];
	    			int l = 1;
	    			if(cnt) l = s[cnt]+1;
	    			int r = i-1;
	    			ans = max(ans, a[t]*(r-l+1));
	    		}
	    		s[++cnt] = i;
	    	}
	    }
	    cout<<ans<<endl;
	}
    return 0;
}

B - TT’s Magic Cat

题意

给你一组数据,n个数,q次操作,每次操作对l到r之间的数都加上c。
输出操作后的n个数。

思路

经典的差分题, 这ppt极好
Week5 W(A - 最大矩形)(B - TT's Magic Cat)(C - 平衡字符串)(D - 滑动窗口)

代码

#include<iostream>
#define llong long long
#define For(i,a,n) for(register int i=a;i<=n;i++)
using namespace std;

const int maxn = 200005;
llong n, q;
llong a[maxn], b[maxn];

int main(){
    ios::sync_with_stdio(false);
    cin>>n>>q;
    For(i,1,n){
    	cin>>a[i];
    	b[i]=a[i]-a[i-1];
    }
    For(i,1,q){
    	llong l,r,c;
    	cin>>l>>r>>c;
    	b[l]+=c, b[r+1]-=c;
    }
    For(i,1,n){
    	b[i]+=b[i-1];
    	cout<<b[i]<<" ";
    }
    cout<<endl;
    return 0;
}

C - 平衡字符串

题意

Week5 W(A - 最大矩形)(B - TT's Magic Cat)(C - 平衡字符串)(D - 滑动窗口)

思路

尺取。
先遍历一下字符串,检查一下QWER哪个字符多了(每一个字符的数量应该是n/4),然后我们尺取字符串,在尺取范围内的字符包含了所有多余的字符即是符合要求的,记录答案,左界++;否则,右界++。

代码

#include<iostream>
#include<map>
#define llong long long
#define For(i,a,n) for(register int i=a;i<=n;i++)
using namespace std;

const int maxn = 100005;

string str;
map<char, int> M{{'Q',0},{'W',1},{'E',2},{'R',3}};
int over[4], sv[4]; //Q:0 W:1 E:2 R:3
int ans;

int jg()
{
	int flag = 1;
	For(i,0,3)
		if(sv[i]>0)
			flag = 0;
	return flag;
}

int main(){
    ios::sync_with_stdio(false);
    cin>>str;
    int len = str.length();
    ans = len;
    int a = len/4;
    For(i,0,len-1) {
    	over[M[str[i]]]++;
    }
    For(i,0,3){
    	over[i] -= a;
    	over[i] = (over[i]>0)?(over[i]):0;
    }
    int flag = 1;
    For(i,0,3){
    	sv[i] = over[i];
    	if(over[i])
    		flag = 0;
    }
    if(flag){
    	cout<<0<<endl;
    	return 0;
    }
    int l=0, r=0;
    while(l<=r && r!=len){
    	int t = M[str[r]];
    	int tt = M[str[l]];
    	if(jg()){
    		if(over[tt]) sv[tt]++;
    		ans = min(ans, r-l);
    		l++;
    	}
    	else{
    		if(over[t]) sv[t]--; 
    		r++;
    	}
    }
    cout<<ans<<endl;
    return 0;
}

D - 滑动窗口

题意

Week5 W(A - 最大矩形)(B - TT's Magic Cat)(C - 平衡字符串)(D - 滑动窗口)

思路

单调队列
这题用deque和list都可以。(需要对前(front)和后(back)的操作)
维护一个最大值的队列和一个最小值的队列两个单调队列
先单独处理前m个的最大和最小值,然后 l++,r++处理。

处理单调队列:
????最小值:遍历新值(更新r)。空队或者大于队尾的值则从后面入队;否则一直将队尾弹出直到空栈或者队尾的值小于它。记录一个vMin表示是否已经将其弹出(失去当最小值的资格)。在更新左端点 l 的时候,如果已经弹出过,则不操作,反之则将队首弹出(此时左端点 l 肯定是最小值)。

最大值同理

每次处理完记录两个队列的队首元素(最大和最小值)

代码

#include<iostream>
#include<queue>
#define llong long long
#define For(i,a,n) for(register int i=a;i<=n;i++)
using namespace std;

const int maxn = 1000005;
int n, m, cnt;
int A[maxn];
int vMax[maxn], vMin[maxn];
int ans[3][maxn];
deque<int> dmax;
deque<int> dmin;

int main(){
    ios::sync_with_stdio(false);
    cin>>n>>m;
    For(i,1,n) cin>>A[i];
    For(i,1,m){
    	if(dmax.empty()){
    		dmax.push_back(i);
    	}
    	else{
    		int t = dmax.back();
    		while(A[i]>=A[t]){
    			dmax.pop_back();
    			vMax[t] = 1;
    			if(dmax.size())
    				t = dmax.back();
    			else break;
    		}
    		dmax.push_back(i);
    	}
    	if(dmin.empty()){
    		dmin.push_back(i);
    	}
    	else{
    		int t = dmin.back();
    		while(A[i]<=A[t]){
    			dmin.pop_back();
    			vMin[t] = 1;
    			if(dmin.size()) 
    				t = dmin.back();
    			else break;
    		}
    		dmin.push_back(i);
    	}
    }

    ans[1][++cnt] = A[dmax.front()];
    ans[2][cnt] = A[dmin.front()];
    int l = 1, r = m;
    while(r!=n){
    	l++, r++;
    	if(!vMax[l-1]) dmax.pop_front();
    	if(!vMin[l-1]) dmin.pop_front();
    	if(dmax.empty()) 
    		dmax.push_back(r);
    	else{
    		int tmax = dmax.back();
	    	while(A[r]>=A[tmax]){
	    		dmax.pop_back();
	    		vMax[tmax] = 1;
	    		if(dmax.size())
	    			tmax = dmax.back();
	    		else break;
	    	}
	    	dmax.push_back(r);
	    }
	    if(dmin.empty())
	    	dmin.push_back(r);
	    else{
	    	int tmin = dmin.back();
	    	while(A[r]<=A[tmin]){
	    		dmin.pop_back();
	    		vMin[tmin] = 1;
	    		if(dmin.size()) 
	    			tmin = dmin.back();
	    		else break;
	    	}
	    	dmin.push_back(r);
	    }
    	ans[1][++cnt] = A[dmax.front()];
    	ans[2][cnt] = A[dmin.front()];
    }
    For(i,1,cnt){
    	cout<<ans[2][i]<<" ";
    }
    cout<<endl;
    For(i,1,cnt){
    	cout<<ans[1][i]<<" ";
    }
    cout<<endl;
    return 0;
}
相关标签: 差分法 队列