zoukankan      html  css  js  c++  java
  • 【LOJ】#2430. 「POI2014」沙拉餐厅 Salad Bar

    题解

    波兰人的j是苹果,p是橘子
    还真是跟中国过不去啊= =写的时候很难受

    我们先求出每个点作为起点,能延伸到的最大长度,这个可以处理成前缀和,查询一下区间最小值是不是小于0,用st表实现,如果区间最小值大于等于0,那么这段区间,以该点作为起点是合法的

    然后求出每个点作为终点能延伸到的最大长度,处理成后缀和

    然后枚举每个点作为起点,找出能延伸的最长右端点,然后再次二分答案,如果二分到的是mid,且mid到ri[i]中的最小值小于等于该点,那么右端点一定可以再往右,否则往左

    三次二分答案,三次st表,比较神奇。。。

    代码

    #include <iostream>
    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #include <vector>
    #include <set>
    #include <cmath>
    #include <bitset>
    #include <queue>
    #define enter putchar('
    ')
    #define space putchar(' ')
    //#define ivorysi
    #define pb push_back
    #define mo 974711
    #define pii pair<int,int>
    #define mp make_pair
    #define fi first
    #define se second
    #define MAXN 100005
    #define eps 1e-12
    using namespace std;
    typedef long long int64;
    typedef double db;
    template<class T>
    void read(T &res) {
        res = 0;char c = getchar();T f = 1;
        while(c < '0' || c > '9') {
    	if(c == '-') f = -1;
    	c = getchar();
        }
        while(c >= '0' && c <= '9') {
    	res = res * 10 - '0' + c;
    	c = getchar();
        }
        res = res * f;
    }
    template<class T>
    void out(T x) {
        if(x < 0) {x = -x;putchar('-');}
        if(x >= 10) out(x / 10);
        putchar('0' + x % 10);
    }
    int N,sum[MAXN],st[MAXN][20],len[MAXN],ri[MAXN],le[MAXN];
    char s[MAXN];
    int Qmin(int l,int r) {
        int t = len[r - l + 1];
        return min(st[l][t],st[r - (1 << t) + 1][t]);
    }
    void Solve() {
        read(N);
        scanf("%s",s + 1);
        for(int i = 1 ; i <= N ; ++i) {
    	if(s[i] == 'j') sum[i] = sum[i - 1] - 1;
    	else sum[i] = sum[i - 1] + 1;
    	st[i][0] = sum[i];
        }
        for(int i = 2 ; i <= N ; ++i) len[i] = len[i / 2] + 1;
        for(int j = 1 ; j <= 18 ; ++j) {
    	for(int i = 1 ; i <= N ; ++i) {
    	    if(i + (1 << j) - 1> N) break;
    	    st[i][j] = min(st[i][j - 1],st[i + (1 << j - 1)][j - 1]);
    	}
        }
        for(int i = 1 ; i <= N ; ++i) {
    	if(s[i] == 'j') continue;
    	int L = i,R = N;
    	while(L < R) {
    	    int mid = (L + R + 1) >> 1;
    	    if(Qmin(i,mid) - sum[i - 1] >= 0) L = mid;
    	    else R = mid - 1;
    	}
    	ri[i] = R;
        }
        memset(sum,0,sizeof(sum));
        for(int i = N ; i >= 1 ; --i) {
    	if(s[i] == 'j') sum[i] = sum[i + 1] - 1;
    	else sum[i] = sum[i + 1] + 1;
    	st[i][0] = sum[i];
        }
        for(int j = 1 ; j <= 18 ; ++j) {
    	for(int i = 1 ; i <= N ; ++i) {
    	    if(i + (1 << j) - 1 > N) break;
    	    st[i][j] = min(st[i][j - 1],st[i + (1 << j - 1)][j - 1]);
    	}
        }
        for(int i = 1 ; i <= N ; ++i) {
    	if(s[i] == 'j') {le[i] = N;continue;}
    	int L = 1,R = i;
    	while(L < R) {
    	    int mid = (L + R) >> 1;
    	    if(Qmin(mid,i) - sum[i + 1] >= 0) R = mid;
    	    else L = mid + 1;
    	}
    	le[i] = L;
        }
        for(int i = 1 ; i <= N ; ++i) st[i][0] = le[i];
        for(int j = 1 ; j <= 18 ; ++j) {
    	for(int i = 1 ; i <= N ; ++i) {
    	    if(i + (1 << j) - 1 > N) break;
    	    st[i][j] = min(st[i][j - 1],st[i + (1 << j - 1)][j - 1]);
    	}
        }
        int ans = 0;
        for(int i = 1 ; i <= N ; ++i) {
    	if(ri[i] >= i) {
    	    int L = i,R = ri[i];
    	    while(L < R) {
    		int mid = (L + R + 1) >> 1;
    		if(Qmin(mid,ri[i]) <= i) L = mid;
    		else R = mid - 1;
    	    }
    	    ans = max(ans,R - i + 1);
    	}
        }
        out(ans);enter;
    }
    int main() {
    #ifdef ivorysi
        freopen("f1.in","r",stdin);
    #endif
        Solve();
    }
    
  • 相关阅读:
    使用Python将excel文件中的数据提取到txt中
    多项式加法的链表实现
    hdu 5976 Detachment 逆元的应用
    JavaScript 全局函数
    JavaScript 事件句柄
    JavaScript 运算符
    纯Javascript 实现的日历 ,在IE所有版本浏览器上测试通过,火狐、谷歌、360、QQ等浏览器均兼容,理论上均兼容所有浏览器
    HTML ASCII 代码
    JavaScript 浏览器版本判定
    Delphi WebBrowser内核版本修改
  • 原文地址:https://www.cnblogs.com/ivorysi/p/9203861.html
Copyright © 2011-2022 走看看