数据结构之单调队列

A - Subsequence

https://www.cnblogs.com/648-233/p/11156168.html 最近真的是疯狂写bug我也是醉了。先是用queue然后下面有个地方是要从前往后回溯的不能pop要pop_front所以只能用deque还找了好一会。然后getminngetmax的while又循环找了好久。然后初始化。最后发现不能简单地pop之前的数据还会影响后面。这个不是有区间限制的那种题。自闭。乖乖用数组写。喵了个咪的。正解不放了,看连接。双端队列ac的。最后是我第二次写的 这道题第二次写的时候对第一次已经基本没有印象。今天跟朋友聊天觉得自己学习有很大的方法问题。没有认真思考算法,每次只看一道题。这是不对的,所以有把之前的题领出来做,接下来说下我第二次写的感受。 首先已经知道这是单调队列了。 所以就想存一个最大值一个最小值。后来发现不能只调整尾部。差值大于k就需要调整头部了,否则最大值或最小值一直不变或者变得更大 而调整头部需要判断是决定最大值(最小)要变小(大),head往后缩,结论是谁坐标在前面谁变(不解释思考一下)所以原本在队列里村的是值,现在只能存坐标了 简单来讲就这两个坑点。 有一个点不明白。为什么是 index=haha1[ head1++]; 不是 head1++; index=haha1[ head1++];

自己写的

#include<iostream>
#include <algorithm>
using namespace std;
const int maxn=100000+5;
int main()
{
    int a[maxn];
    int haha1[maxn],haha2[maxn];
    int n,m,k;
    while(cin>>n>>m>>k) {
        int head1 = 0, head2 = 0, tail1 = 0, tail2 = 0, index = 0, maxx = 0;
        for (int i = 1; i <= n; i++) {
            cin >> a[i];
            while (head1 < tail1 && a[i] <a[ haha1[tail1 - 1]])tail1--;
            haha1[tail1++] = i;
            while (head2 < tail2 && a[i] >a[ haha2[tail2 - 1]])tail2--;
            haha2[tail2++] = i;
            int e = a[haha2[head2]] - a[haha1[head1]];
//            cout<<e<<haha2[head2]<<haha1[head1]<<endl;
            while(head1<tail1&&head2<tail2&&e>k){
                if(haha1[head1]<haha2[head2]){
                    index=haha1[ head1++];
                }
                else {
                    index=haha2[head2++];
                }
                e = a[haha2[head2]] - a[haha1[head1]];
            }
            if (head1<tail1&&head2<tail2&&e >= m ){
                maxx = max(maxx, i-index);
            }
        }
        cout << maxx << endl;
    }
}

(好像错了)双端

#include <cstdio>
#include <queue>
using namespace std;
 
const int N = 1000005;
typedef pair<int,int> P;
 
deque<P> Q1;
deque<P> Q2;
int ans1[N],ans2[N];
 
int main ()
{
	int n,k,x,i;
	while (~scanf("%d%d",&n,&k))
	{
		while (!Q1.empty()) Q1.pop_back();
		while (!Q2.empty()) Q2.pop_back();
		for (i=0;i<n;i++)
		{
			scanf("%d",&x);
			while (!Q1.empty() && Q1.back().first >= x)
				Q1.pop_back();
			Q1.push_back(P(x,i));
			while (!Q1.empty() && Q1.front().second <= i-k)
				Q1.pop_front();
			ans1[i] = Q1.front().first;
			
			while (!Q2.empty() && Q2.back().first <= x)
				Q2.pop_back();
			Q2.push_back(P(x,i));
			while (!Q2.empty() && Q2.front().second <= i-k)
				Q2.pop_front();
			ans2[i] = Q2.front().first;
		}
		for (i=k-1;i<n;i++)
			printf(i==n-1?"%d\n":"%d ",ans1[i]);
		for (i=k-1;i<n;i++)
			printf(i==n-1?"%d\n":"%d ",ans2[i]);
	}
	return 0;
}

B - Largest Rectangle in a Histogram

思路基本是对的,写挫了。下次重写一遍。以下为优秀代码(感觉都不用单调队列思想

https://blog.csdn.net/SSL_hzb/article/details/81697717

#include<cstdio>
#include<algorithm>
using namespace std;
int n,a,b,stack[100001],len,w[100001],s;
long long ans;
int main()
{
    while (scanf("%d",&n),n)
    {
        len=ans=0;
        for (int i=1;i<=n+1;i++)
        {
            if (i!=n+1) scanf("%d",&a);
            else a=0;//最后没有一个递减的来更新答案,所以枚举到n+1的时候弄一个很小的值
            if (a>stack[len])
            {
                stack[++len]=a;
                w[len]=1;
            }
            else
            {
                s=0;
                while (a<stack[len])
                {
                    s+=w[len];
                    ans=max(ans,(long long)s*stack[len]);//更新答案
                    len--;
                }
                stack[++len]=a;w[len]=s+1;//新加入一个削掉多余部分的矩形
            }
        }
        printf("%lld\n",ans);
    }
}

之前代码就不放上来了原本有个地方写错了。但是问题是超时不管了下次再写一遍

C - Second My Problem First

根据题解写的数组。但是这个用que感觉简单。第二遍写的时候发现不难,就是num不要特地去求会超时真的最近傻到爆ai。
#include<iostream>
#include <queue>
using namespace std;
int mod;
struct yyy{
    int val,i;
    yyy(int a,int c):val(a),i(c){}
};
deque<yyy>que;
void init(){
    while(!que.empty())que.pop_back();
}
int main()
{
    int n,m;
    while(~scanf("%d%d%d",&n,&m,&mod)) {
        long long ans = 1,num=1;
        init();
        for (int i = 1; i <= n; i++) {
            num =num*m%mod;
//            cout<<num<<endl;
            while (!que.empty() && i - que.back().i > m)que.pop_front();
            while (!que.empty() && num < que.back().val)que.pop_back();
            que.push_back(yyy(num,i));
            ans = ans * que.front().val % mod;
        }
        cout << ans << endl;
    }
}

D - Alice's mooncake shop

#include<iostream>
#include <queue>
using namespace std;
struct node{
    int valnum,hour;
    node(int x,int y):valnum(x),hour(y){}
};
//string mon[20]={"","Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov","Dec"};
//int d[20]={0,31,28,31,30,31,30,31,31,30,31,30,31};
string mon[20]={"", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov","Dec"};
int d[20]={0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
string M;
deque<node>cost;
queue<node>order;
void init(){
    while(!cost.empty())cost.pop_back();
    while(!order.empty())order.pop();
}
int main() {
    int n, m;
    while (~scanf("%d%d", &n, &m) && (n || m)) {
        init();
        for (int i = 0; i < n; i++) {
            cin >> M;
            int day, year, hour, num;
            scanf("%d%d%d%d", &day, &year, &hour, &num);
            for (int j = 2000; j < year; j++) {
                if (( j % 4 == 0 && j % 100) || j % 400 == 0)day += 366;
                else day += 365;
            }
            int j;
            for (j = 1; j <= 12; j++)
                if (M == mon[j])break;
            for (int k = 1; k < j; k++) {
                if (k == 2 && (( year % 4 == 0 && year % 100) || year % 400 == 0))
                    day += 29;
                else day += d[k];
            }
            day--;
            order.push(node(num, day * 24 + hour));
        }
        int T, S;
        scanf("%d%d", &T, &S);
        long long ans = 0;
        for (int i = 0; i < m; i++) {
            int x;
            scanf("%d", &x);
            while (!cost.empty() && x <= cost.back().valnum + (i - cost.back().hour) * S) {
                cost.pop_back();
            }
            cost.push_back(node(x, i));
            while (!order.empty() && i == order.front().hour) {
                while (!cost.empty() && i - order.front().hour > T)cost.pop_front();
                ans += (cost.front().valnum + (i - cost.front().hour) * S) * order.front().valnum;
                order.pop();
            }
        }
        printf("%lld\n", ans);
    }
}

G - Queue CodeForces - 91B

疯狂读错题,开始以为写过,后来发现基本不一样也是醉了,一改再改后面发现思路不行。 写法样例能过但是数据庞大不可实现为了纪念改了那么久bug还是给放下吧
#include<iostream>

const int MAXM=50000;

int a[MAXM+5],s[MAXM+5],st[(MAXM<<2)+5];

#include <string.h>
using namespace std;
void build(int o,int l,int r){
    if(l==r)st[o]=0;
    else{
        int m=l+((r-l)>>1);
        build(o<<1,l,m);
        build((o<<1)|1,m+1,r);
        st[o]=max(st[o<<1],st[(o<<1)|1]);
    }
}

void update(int o,int l,int r,int ind,int ans){
    if(l==r){
        st[o]=ans;
//        cout<<l<<ans<<endl;
        return;
    }
    int m=l+((r-l)>>1);
    if(ind<=m){
        update(o<<1,l,m,ind,ans);
    }
    else{
        update((o<<1)|1,m+1,r,ind,ans);
    }
    st[o]=max(st[o<<1],st[(o<<1)|1]);//递归回之后用儿子结点更新父节点(此处是区间最大值)
}
int query(int o,int l,int r,int ql,int qr){
//    cout<<l<<" "<<r<<ql<<qr<<endl;
    if(ql>r||qr<l) return 0;
    if(ql<=l&&qr>=r) {
//        cout<<l<<" "<<r<<ql<<qr<<endl;
    return st[o];}
    int m=l+((r-l)>>1);
    int p1=query(o<<1,l,m,ql,qr),p2=query((o<<1)|1,m+1,r,ql,qr);
    return max(p1,p2);
}
int main()
{
    int n;cin>>n;
    build(1,1,100);
    for(int i=0;i<n;i++){
        cin>>a[i];
    }
    for(int i=n-1;i>=0;i--) {
        update(1, 1, 100, a[i], i);
//        cout<<query(1,1,100,1,10)<<endl;
        s[i]=query(1,1,100,1,a[i]-1)-i-1;
    }
    for(int i=0;i<n;i++) {
        if (s[i] >= 0)cout << s[i] << endl;
        else cout << -1 << endl;
    }
}

https://blog.csdn.net/a664607530/article/details/52909700
Queue

#include <map>
#include <set>
#include <stack>
#include <queue>
#include <cmath>
#include <ctime>
#include <vector>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
#define INF 0x3f3f3f3f
#define inf (-((LL)1<<40))
#define lson k<<1, L, (L + R)>>1
#define rson k<<1|1,  ((L + R)>>1) + 1, R
#define mem0(a) memset(a,0,sizeof(a))
#define mem1(a) memset(a,-1,sizeof(a))
#define mem(a, b) memset(a, b, sizeof(a))
#define FIN freopen("in.txt", "r", stdin)
#define FOUT freopen("out.txt", "w", stdout)
#define rep(i, a, b) for(int i = a; i <= b; i ++)
#define dec(i, a, b) for(int i = a; i >= b; i --)
#define rmq_log2(x,val) while((1<<(x+1))<=val)x++;

template<class T> T MAX(T a, T b) { return a > b ? a : b; }
template<class T> T MIN(T a, T b) { return a < b ? a : b; }
template<class T> T GCD(T a, T b) { return b ? GCD(b, a%b) : a; }
template<class T> T LCM(T a, T b) { return a / GCD(a,b) * b;    }

typedef long long LL;
const int maxn =2e5+5;
const int MAXM = 110000;
const double eps = 1e-8;
LL MOD = 1000000007;


int n,k;
int a[maxn],dp[maxn][20];
void rmq_init()
{
    for(int i=1;i<=n;i++)
        dp[i][0]=a[i];//初始化
    for(int j=1;(1<<j)<=n;j++)
        for(int i=1;i+(1<<j)-1<=n;i++)
            dp[i][j]=max(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
}
int rmq(int l,int r)
{
    int k=0;
    rmq_log2(k,r-l+1)
    return max(dp[l][k],dp[r-(1<<k)+1][k]);
}
int solve(int num){
    int ans=0;
    int x=n/num;
//    int flag=0;
//    if(num==1)flag=1;
    for(int i=1;i<=num;i++){
        ans+=rmq((i-1)*x+1,i*x);
//        if(flag)cout<<ans<<endl;
        if(ans>k) return 1;
    }
    if(ans>k)return 1;
    else return 0;
}
int main()
{
    while(cin>>n>>k&&!(n==-1&&k==-1)) {
        int sum=0,flag=0;
        rep(i, 1, n) {
            cin >> a[i];
            sum += a[i];
            if (a[i] >= k)flag = 1;
        }
        if (flag == 1){cout << 1 << endl;continue;}
        if (sum < k){cout << -1 << endl;continue;}
        rmq_init();
        int l = 1, r = n;/*l=2*/
        int answ,mid;
        while (l <= r) {/*l<r*/
            int mid = (l + r) / 2;
//            cout<<mid<<endl;
            if (solve(mid)) {//这里传的是组的个数
                r = mid - 1;/*l=mid+1*/
                answ = mid;
//                cout<<mid<<endl;
            } else l = mid + 1;
        }
        cout << answ << endl;/*n/answ*/
    }
}

I - Cornfields POJ - 2019

250*250直接暴力一下。scanf真好。cin会超时。
#include <stdio.h>
#include <algorithm>
const int inf=10000000;
using namespace std;
int main()
{
    int bigedge,smalledge,coun;
    scanf("%d%d%d",&bigedge,&smalledge,&coun);
    int a[300][300],f[300][270];
    for(int i=1;i<=bigedge;i++)
        for(int j=1;j<=bigedge;j++){
            scanf("%d",&a[i][j]);
        }
    while(coun--){
        int x,y;
        scanf("%d%d",&x,&y);
        if(!f[x][y]){
            int minn=inf,maxx=0;
        for(int i=x;i<x+smalledge;i++)
            for(int j=y;j<y+smalledge;j++){
                minn=min(a[i][j],minn);
                maxx=max(a[i][j],maxx);
            }
            f[x][y]=maxx-minn;
        }
        printf("%d\n",f[x][y]);
    }
}

学习st算法二级rmq算法。
记忆化搜索https://blog.csdn.net/hjf1201/article/details/78680814

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值