week5 实验+作业

记录week5的实验一道题+作业四道题
画图、最大矩形、TT’s Magic Cat、平衡字符串、滑动窗口
作业:

最大矩形:

给一个直方图,求直方图中的最大矩形的面积。例如,下面这个图片中直方图的高度从左到右分别是2, 1, 4, 5, 1, 3, 3, 他们的宽都是1,其中最大的矩形是阴影部分。
Input
输入包含多组数据。每组数据用一个整数n来表示直方图中小矩形的个数,你可以假定1 <= n <= 100000.
然后接下来n个整数h1, …, hn, 满足 0 <= hi <= 1000000000.
这些数字表示直方图中从左到右每个小矩形的高度,每个小矩形的宽度为1。 测试数据以0结尾。
Output
对于每组测试数据输出一行一个整数表示答案。
Sample Input
7 2 1 4 5 1 3 3
4 1000 1000 1000 1000
0
Sample Output
8
4000

       这道题的数据量是1e5,也就是说依次枚举的n方解法是跑不出来的,所以用单调栈的方法降低时间复杂度。
       大致思想是:遍历数组,每次遇到不符合条件的,就从栈里弹出元素,并将弹出元素的宽度更新,直到符合条件或栈为空便将该元素入栈。
       需要设结构体node表示元素高和下标维护两个单调栈s和e,s用来找i向右最大可以延申的宽度,e找i向左最大延申的宽度。这样就的得到了i点最大矩形的宽度,乘以i点的高就得出i点矩形面积。
       注意为了最后将栈清空,把栈遍历方向的最后一位置为-1.

#include<iostream>
#include<stack>
#include <algorithm>
#include<cstring>
using namespace std;
int n;

long long int a[100005];
long long int L[100005];long long int R[100005]; 

struct node{
long long int h;
long long int x;
};

int main(){
while(1){
    scanf("%d",&n);		
    if(n==0)break;
	
	stack<node>s; long long int ans=0;
     
    for(int i=1;i<=n;i++){scanf("%lld",&a[i]);}a[0]=-1;a[n+1]=-1;
    for(int i=1;i<=n+1;i++){
    	if(s.empty()||a[i]>=s.top().h)
		{
		 node t;t.h=a[i];t.x=i;
		 s.push(t);
		}
        else if(a[i]<s.top().h)
		{
		   while(!s.empty()&&a[i]<s.top().h)
		   {
		    node t;t.h=s.top().h;t.x=s.top().x; // long long int mj=(i-t.x)*t.h;
		    R[t.x]=i-t.x;                                    //ans=max(ans,mj);
			s.pop();
		   }
		    node t;t.h=a[i];t.x=i;
		    s.push(t);
		}	
	}
//for(int i=1;i<n+1;i++)cout<<R[i]<<" ";
	stack <node>e;

	 for(int i=n;i>=0;i--){
    	if(e.empty()||a[i]>=e.top().h)
		{
		 node t;t.h=a[i];t.x=i;
		 e.push(t);
		}
        else if(a[i]<e.top().h)
		{
		   while(!e.empty()&&a[i]<e.top().h)
		   {
		    node t;t.h=e.top().h;t.x=e.top().x; // long long int mj=(i-t.x)*t.h;
		    L[t.x]=t.x-i;                                    //ans=max(ans,mj);
			e.pop();
		   }
		    node t;t.h=a[i];t.x=i;
		    e.push(t);
		}	
	}
//cout<<endl;
//for(int i=1;i<n+1;i++)cout<<L[i]<<" ";
	for(int i=1;i<=n;i++)
	{  long long int te=(R[i]+L[i]-1)*a[i];ans=max(ans,te);}
     printf("%lld\n",ans);
	
	}	
	return 0;
}

TT’s Magic Cat:

在这里插入图片描述

Input
4 2
-3 6 8 4
4 4 -2
3 3 1
Output
-3 6 9 2

这道题数据量是1e6,n方肯定做不出来,于是将输入的数组a表示为差分的形式成为数组b,其中b[i]=a[i]-a[i-1]。这样求ai就成为了求b0+b1+……+bi;修改a[L]到a[R]也就简化为了修改b[i+1],b[L];于是是一个on的算法.
但是写代码的时候发现有一些问题:
1、提交时用 G++ 会TLE 而 C++不会
2、 cin cout 与scanf printf混用会WA掉?????

#include<iostream>
using namespace std;
int n,q;
    	int l,r,c;
int a[300005];
int b[300005];
	long long int re=0;
// 1、G++ 会TLE C++不会       2、    cin cout  与scanf printf混用会WA???????why???
int main(){
	cin>>n>>q;
	cin>>a[0];b[0]=a[0];
    for(int i=1;i<n;i++){cin>>a[i];b[i]=a[i]-a[i-1];   }
    for(int st=0;st<q;st++)
    {
          cin>>l>>r>>c;
          b[l-1]+=c;
		  b[r]-=c;      		
	}
	for(int i=0;i<n;i++)
	{re=re+b[i];cout<<re<<" ";}
	return 0;
}

平衡字符串

一个长度为 n 的字符串 s,其中仅包含 ‘Q’, ‘W’, ‘E’, ‘R’ 四种字符。

如果四种字符在字符串中出现次数均为 n/4,则其为一个平衡字符串。

现可以将 s 中连续的一段子串替换成相同长度的只包含那四个字符的任意字符串,使其变为一个平衡字符串,问替换子串的最小长度?

如果 s 已经平衡则输出0。

这道题同样要用复杂度n的方法解,用LR表示边界,sum1-4表示L-R之外的QWER的数量。在对L-R填平之后,看L-R剩余的字符数目over,如果满足over%4==0并且over大于等于0,L就可以向右移。否则就是R就向右移动,并在移动之后更新sum1-4;

#include<iostream>
using namespace std;
string s;
int n;
int l,r;
int sum1,sum2,sum3,sum4,maxx;
int total;
int over;
int ans;
int main(){
	cin>>s;n=s.size();ans=n;
	for(int i=0;i<n;i++)
	{
		if(s[i]=='Q')sum1++;
		else if(s[i]=='W')sum2++;
		else if(s[i]=='E')sum3++;
		else if(s[i]=='R')sum4++;
	}l=0;r=0;
	if(sum1==sum2&&sum3==sum4&&sum1==sum3)ans=0;
	else{
		if(s[r]=='Q')sum1--;
		else if(s[r]=='W')sum2--;
		else if(s[r]=='E')sum3--;
		else if(s[r]=='R')sum4--;
while(1){
	maxx=max(max(sum1,sum2),max(sum3,sum4));
	total=r-l+1;
	over=total-(4*maxx-sum1-sum2-sum3-sum4);
//	cout<<l<<" "<<r<<" "<<total<<" "<<over<<" "<<ans<<endl;
	if(over%4==0&&over>=0){//平衡 
	     ans=min(total,ans);
      	if(s[l]=='Q')sum1++;
		else if(s[l]=='W')sum2++;
		else if(s[l]=='E')sum3++;
		else if(s[l]=='R')sum4++;
        l++;//if(l>=n)break;		     	
	}
	else{
		if(r>=n-1)break;
		if(s[r+1]=='Q')sum1--;
		else if(s[r+1]=='W')sum2--;
		else if(s[r+1]=='E')sum3--;
		else if(s[r+1]=='R')sum4--;
		r++;
	}
}
}	cout<<ans; 

	return 0;
} 

滑动窗口:
在这里插入图片描述
这道题用单调队列解决,c++的STL deque可以用来做队列,因为它可以操作队尾元素。
维护两个deque 一个求最小,一个求最大,然后依次遍历元素,如果当前元素ai符合条件,则入队,否则就pop队尾。同时操作完成后要判断是否超出窗口K,若超,则pop队首。最后要更新最小元素 最大元素。

#include<iostream>
#include<cstdio>
#include<deque>
using namespace std;
const int maxn=1e6+6;
struct node
{
    int ele,i;
};
int small[maxn],big[maxn],a[maxn];
int main()
{
    int n,k,i;
    node t;
    deque<node>q;
    deque<node>qq;
    scanf("%d%d",&n,&k);
    scanf("%d",&t.ele);
    t.i=1;
    a[1]=t.ele;
    small[1]=t.ele;
    q.push_back(t);
    for(i=2;i<=n;i++)
    {
        scanf("%d",&a[i]);
        t.ele=a[i];
        t.i=i;
        while(!q.empty()&&q.back().ele>a[i])
            q.pop_back();
        q.push_back(t);
        if(!q.empty()&&q.front().i<i-k+1)
            q.pop_front();
        small[i]=q.front().ele;
    }
    big[1]=a[1];
    t.ele=a[1];
    t.i=1;
    qq.push_back(t);
    for(i=2;i<=n;i++)
    {
        t.ele=a[i];
        t.i=i;
        while(!qq.empty()&&qq.back().ele<a[i])
            qq.pop_back();
        qq.push_back(t);
        if(!qq.empty()&&qq.front().i<i-k+1)
            qq.pop_front();
        big[i]=qq.front().ele;
    }
    for(i=k;i<n;i++)
        printf("%d ",small[i]);
    printf("%d\n",small[n]);
    for(i=k;i<n;i++)
        printf("%d ",big[i]);
    printf("%d\n",big[n]);
}

实验:
csp 2015 12-3 画图:
在这里插入图片描述

这道题和迷宫老鼠比较像,初始化char数组做地图,然后按照操作更新地图,划线比较简单,填充可以dfs可以bfs。我用了bfs填充,设置四个方向,遇到的元素如果不是-、|、+或者超出边界就设置为输入的字符c。
但是这道题有很多要注意的地方。
1、要注意遇到+也要置为+
2、注意不超出边界
3、输出地图的时候注意ij遍历的顺序和范围……因为他是倒着的……

#include<bits/stdc++.h> 
using namespace std;
int m,n,opsum;
char _map[105][105];
struct node{
	int x;
	int y;
};
struct offset{
	int dx;
	int dy;
}offset[4];

void pre(){
	for(int i=0;i<105;i++)
	for(int j=0;j<105;j++)
	_map[i][j]='.';
    offset[0].dx=0;offset[0].dy=1;
    offset[1].dx=1;offset[1].dy=0;
    offset[2].dx=0;offset[2].dy=-1;
    offset[3].dx=-1;offset[3].dy=0;
}

void output(){
	for(int i=n-1;i>=0;i--)
	{
	for(int j=0;j<m;j++)
	{
	cout<<_map[j][i];
    }
    cout<<endl;
	}

}
void meun(){
	cin>>m>>n>>opsum;
	pre();
	for(int i=0;i<opsum;i++){
	 	int op;scanf("%d",&op);
	if(op==0){
		int x1,x2,y1,y2;
     	cin>>x1>>y1>>x2>>y2;
		if(x1==x2&&y1!=y2){//竖着 
			if(y1>y2){
				int te=y2;y2=y1;y1=te;
			}
			for(int j=y1;j<=y2;j++)
			{
				if(_map[x1][j]=='-'||_map[x1][j]=='+')_map[x1][j]='+';
				else _map[x1][j]='|';
			}
		}
		else if(x1!=x2&&y1==y2){//横着 
			if(x1>x2){
				int te=x2;x2=x1;x1=te;
			}
			for(int j=x1;j<=x2;j++){
			    if(_map[j][y1]=='|'||_map[j][y1]=='+')_map[j][y1]='+';
			    else _map[j][y1]='-';
			}
		} 	
	}
	else if(op==1){
	queue<node>q;
	int sx,sy;char c;
	cin>>sx>>sy>>c;
	 node p;p.x=sx;p.y=sy;
	 q.push(p);
	 while(!q.empty()){
	 	node now=q.front();
	 	q.pop();
	    for(int j=0;j<4;j++)
	    {
	    	node next;
			next.x=now.x+offset[j].dx;
			next.y=now.y+offset[j].dy;
			if(_map[next.x][next.y]!='|'&&_map[next.x][next.y]!='-'&&_map[next.x][next.y]!='+'&&_map[next.x][next.y]!=c&&next.x<m&&next.y<n&&next.x>=0&&next.y>=0) 
			{
			  q.push(next);_map[next.x][next.y]=c;
			}
		}	
	 }
	
	}	

}
		
output();	
}

int main(){
	
	meun();
	
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值