0x11 栈

  1. 单调栈 栈的基本操作
class MinStack {
public:
    /** initialize your data structure here. */
    int a[5050];
    int mi[5050];
    int tops;
    
    MinStack() {
        tops=0;
    }
    
    void push(int x) {
        a[++tops]=x;
        if(tops==1){
            mi[tops]=x;
        }else{
            mi[tops]=min(mi[tops-1],x);
        }
    }
    
    void pop() {
        tops--;
    }
    
    int top() {
        return a[tops];
    }
    
    int getMin() {
        return mi[tops];
    }
};
  1. 编辑器
    对顶栈 栈的应用 f数组存最大sum
#include <bits/stdc++.h>
using namespace std;

const int maxn = 1e6 + 5 ;
const double pi = acos(-1.0);

int n, m;
int A[maxn], Atop;
int B[maxn], Btop;
int sum[maxn], f[maxn];

signed main() {
    cin >> n;
    string cmd;
    f[0]=-0x3f3f3f3f;
    while(n--) {
        cin >> cmd;
        if(cmd[0] == 'I') {
            cin >> m;
            A[++Atop] = m;
            sum[Atop] = sum[Atop - 1] + A[Atop];
            f[Atop] = max(sum[Atop], f[Atop - 1]);
        } else if(cmd[0] == 'Q') {
            cin >> m;
            cout << f[m] << endl;
        } else if(cmd[0] == 'D') {
            if(Atop)
                Atop--;
        } else if(cmd[0] == 'R') {
            if(Btop == 0)
                continue;
            A[++Atop] = B[Btop--];
            sum[Atop] = sum[Atop - 1] + A[Atop];
            f[Atop] = max(f[Atop - 1], sum[Atop]);
        } else if(cmd[0] == 'L') {
            if(Atop == 0)
                continue;
            B[++Btop] = A[Atop--];
        }
    }
    return 0;
}
  1. 火车进出栈问题
    当入栈 + 出栈火车达到n时 输出 出战的在把栈内pop出即可
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 5 ;
const double pi = acos(-1.0);

int n, m;
int sta[maxn], top;
int que[maxn], head, tail;
int ans;

void dfs(int num) {
    if(ans >= 20)
        return ;
    if(num == n + 1) {
        for(int i = 1; i <= tail; i++) {
            cout << que[i];
        }
        for(int i = top; i; i--) {
            cout << sta[i];
        }
        cout << endl;
        ans++;
        return ;
    }
    if(top) {
        que[++tail] = sta[top--];
        dfs(num);
        sta[++top] = que[tail--];
    }
    sta[++top] = num;
    dfs(num + 1);
    --top;
}

signed main() {
    cin >> n;
    dfs(1);
    return 0;
}
  1. 进出站序列问题 卡特兰数 1 0 序列 一般 1 <= 0 但是最终数量上 0 == 1
    DP 直接膜大数乘除 超时。。。。。。。。。。。orz
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn =2e5 + 5 ;
const int jz = 1e9;

int res[maxn], tt;
bool pr[maxn];
int p[maxn],cnt,chu[maxn];

void init(){
    pr[1]=pr[0]=1;
    for(int i = 2; i < maxn; i++ ){
        if(!pr[i]){
            p[cnt ++ ] = i;
            for(int j = (i << 1); j < maxn; j += i){
                pr[j] = 1;
            }
        }
    }
}

int ges(int n, int ps){
    int s = 0;
    while(n){
        s += n/ps;
        n/=ps;
    }
    return s;
}

void mul(int b){
    int r = 0;
    for(int i = 0;  i <= tt; i ++ ) {
        res[i] = res[i] * b + r;
        r = res[i] / jz;
        res[i] %= jz;
    }
    while(r){
        res[++tt] = r % jz;
        r /= jz;
    }
}

void div(int b){
    int r = 0;
    for(int i = tt; i >= 0; i -- ) {
        res[i] += r * jz;
        r = res[i] % b;
        res[i] /= b;
    } 
    while(!res[tt]) tt--;
}

void out(){
    printf("%lld",res[tt]);
    for(int i = tt - 1; i >= 0; i -- ){
        printf("%09lld",res[i]);
    }puts("");
}

signed main() {
    int n;
    cin >> n;
    init();
    for(int i = 0; i < cnt; i ++) {
        chu[p[i]] = ges(n * 2, p[i]) - ges(n, p[i]) * 2;
    }
    int k = n + 1;
    for(int i = 0;p[i]<=k; i++){
        int s = 0;
        while(k%p[i]==0){
            s ++;
            k/=p[i];
        }
        chu[p[i]] -= s;
    }
    res[0] = 1;
    tt =0 ;
    for(int i =2 ;i <= n*2; i++){
        for(int j = 0; j <chu[i];j++){
            mul(i);
        }
    }
    out();
    return 0;
}

以下重新整理到这里
单调栈
板子。

#include<cstdio>
#include<stack>
using namespace std;
#define ll long long
const int N = 1e5+5;
ll a[N];;
int L[N], R[N], st[N];
int main(){
    int n;
    while(~scanf("%d", &n) && n){
        for(int i = 1; i <= n; i++)
            scanf("%lld", &a[i]);
        int top = 0;
        for(int i = 1; i <= n; i++){
            while(top && a[st[top-1]] >= a[i]) top--;
            L[i] = (top==0) ? 0 : st[top-1];
            st[top++] = i;
        }
        
        top = 0;
        for(int i = n; i >= 1; i--){
            while(top && a[st[top-1]] >= a[i]) top--;
            R[i] = (top==0) ? (n+1) : st[top-1];
            st[top++] = i;
        }
        
        ll ans = 0;
        for(int i = 1; i <= n; i++)
            ans = max(ans, (ll)(R[i]-L[i]-1)*a[i]);
        
        printf("%lld\n", ans);
    }
    return 0;
}

队列

team queue
模拟队列
小组队列
开 2个队列A,B 在开个map什么的记录每个人属于什么队
第一个队列放map人对应属于什么
插入的时候 优先放到 B队列 如果A队列它不再了 插到A尾部 否在不管
pop 时候 如果这个第一队列空了 A弹出它 否在不管

#include <cstdio>
#include <string>
#include <iostream>
#include <map>
#include <queue>
using namespace std;
const int maxn = 1010;

int main (){
	int kase=0,t;
	queue<int> q,pq[maxn];
	map<int,int> team;
	char cmd[10];
	while(scanf("%d",&t)!=EOF&&t){
	while(!q.empty())q.pop();
		team.clear();
		printf("Scenario #%d\n",++kase);
		for(int i=0;i<t;i++){
			int n,x;
			scanf("%d",&n);
			while(n--){
				scanf("%d",&x);
				team[x]=i;
			}
			while(!pq[i].empty())pq[i].pop();
		}
		for(;;){
			int x;
			scanf("%s",cmd);
			if(cmd[0]=='S') {break;}
			if(cmd[0]=='E'){
				scanf("%d",&x);
				int t=team[x];
				if(pq[t].empty()) q.push(t);
				pq[t].push(x);
			}
			if(cmd[0]=='D'){
				int t=q.front();
				printf("%d\n",pq[t].front());
				pq[t].pop();
				if(pq[t].empty()) q.pop();
			}
		}
		cout<<endl;
	}
	return 0;
} 

蚯蚓

这题不太好想orz 首先是坎最长的 不需要考虑 但是每坎一次 其他都会长q 这样维护起来就变难了 所以 我们使用了一个detla
作为整体应该加的数据

每次选出最长的+detla 然后坎了它 因为被砍出得 这轮不会 在涨 所以 p1-q,p2-q; 放回队列 detla+=q;
这样就处理了其他量在变得情况

#include <bits/stdc++.h>
using namespace std;
#define int long long

const int maxn = 1e5 + 5 ;
const double pi = acos(-1.0);

int n, m, q, u, v, t;
priority_queue<int> que;
int a[maxn];

queue<int> q2, q3;

int rmax() {
    int x = -0x3f3f3f3f3f3f3f;
    if(!que.empty())
        x = max(x, que.top());
    if(!q2.empty())
        x = max(x, q2.front());
    if(!q3.empty())
        x = max(x, q3.front());
    if(!que.empty() && x == que.top())
        que.pop() ;
    else if(!q2.empty() && x == q2.front())
        q2.pop() ;
    else
        q3.pop() ;
    return x;
}

signed main() {
    cin >> n >> m >> q >> u >> v >> t;
    for(int i = 1; i <= n; i++)
        cin >> a[i], \
            que.push(a[i]);
    int res = 0;
    for(int i = 1; i <= m; i += 1) {
        int ma = rmax();
        ma += res;
        if(i%t==0) cout << ma << " ";
        int p1 = ma * u / v;
        int p2 = ma - p1;
        res += q;
        q2.push(p1 - res);
        q3.push(p2 - res);
    }
    cout << endl;
    for(int i=1;i<=n+m;i++) {
        int x = rmax();
        if(i%t==0)
            cout << x + res << " ";
    }
    cout << endl;
    return 0;
}

双端队列 待续

单调队列 最大字段和 这玩意应用挺多的 贪心要用 DP要用。。 经常需要它

#include <bits/stdc++.h>
using namespace std;
#define int long long

const int maxn = 3e5 + 5 ;
const double pi = acos(-1.0);

int n, m;
int a[maxn];
int sum[maxn];
int q[maxn], head, tail;

signed main() {
	cin >> n >> m ;
	for(int i = 1 ; i <= n ; i++) {
		cin >> a[i];
		sum[i] = sum[i - 1] + a[i];
	}
	q[1] = 0;
	int l = 1, r = 1;
	int ans = 0;
	for(int i = 1; i <= n; i++) {
		if(l <= r && q[l] < i - m)
			l++; // 队列>M
		ans = max(ans, sum[i] - sum[q[l]]);
		while(l <= r && sum[q[r]] >= sum[i])
			r--;
		q[++r] = i;
	}
	cout << ans << endl;
	return 0;
}