Good Bye 2015 F - New Year and Cleaning

F - New Year and Cleaning

这题简直是丧心病狂折磨王。。

思路:容易想到这样一个转换,把整个矩形一起移动,矩形移出去的时候相当于一行或者一列。

为了优化找到下一个消去的点,我先把原数组扩大两倍,用了st表加二分去找,然后就MLE, 我又换了

线段树TLE,最后不把数组扩大两倍ST表+二分过的。。

 

每次消去的点都是不变的,所以可以做到线性复杂度。

#include<bits/stdc++.h>
#define LL long long
#define fi first
#define se second
#define mk make_pair
#define PII pair<int, int>
#define PLI pair<LL, int>
#define ull unsigned long long
using namespace std;

const int N = 5e5 + 7;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 + 7;

int k, n, m, X[N], Y[N], Log[N];
char s[N];

struct ST {
    int dp[N][20],ty;
    void build(int n, int b[], int _ty) {
        ty = _ty;
        for(int i = 1; i <= n; i++) dp[i][0] = ty * b[i];
        for(int j = 1; j <= Log[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 query(int x, int y) {
        int k = Log[y - x + 1];
        return ty * max(dp[x][k], dp[y-(1<<k)+1][k]);
    }
} mxx, mnx, mxy, mny;

void walk(int &x, int &y, char c) {
    if(c == 'R') y++;
    else if(c == 'L') y--;
    else if(c == 'U') x--;
    else x++;
}

bool check(int l, int r, int x, int y, int lenr, int lenc) {
    int mxX = mxx.query(l, r) - X[l-1];
    int mnX = mnx.query(l, r) - X[l-1];
    int mxY = mxy.query(l, r) - Y[l-1];
    int mnY = mny.query(l, r) - Y[l-1];
    if(x+mxX+lenr > n || x+mnX < 0 || y+mxY+lenc > m || y+mnY < 0) return true;
    return false;
}

int main() {
    for(int i = -(Log[0]=-1); i < N; i++)
        Log[i] = Log[i - 1] + ((i & (i - 1)) == 0);

    scanf("%d%d%d%s", &k, &n, &m, s + 1);
    int x = 0, y = 0, L = 0, R = 0, D = 0, U = 0, p = 0;
    for(int i = 1; i <= k; i++) {
        walk(x, y, s[i]);
        L = min(L, y); R = max(R, y);
        U = min(U, x); D = max(D, x);
    }
    if(!x && !y) {
        if(R - L + 1 <= m && D - U + 1 <= n) {
            puts("-1");
            return 0;
        }
    }
    x = 0, y = 0;
    for(int i = 1; i <= k; i++) {
        walk(x, y, s[i]);
        X[i] = x; Y[i] = y;
    }

    mxx.build(k, X, 1);
    mnx.build(k, X, -1);
    mxy.build(k, Y, 1);
    mny.build(k, Y, -1);

    x = 0, y = 0;
    int lenr = n, lenc = m;
    LL ans = 0, t = 0;
    while(lenr && lenc) {
        int l = p + 1, r = min(k, p + k), pos = -1;
        while(l <= r) {
            int mid = l + r >> 1;
            if(check(p + 1, mid, x, y, lenr, lenc)) r = mid - 1, pos = mid;
            else l = mid + 1;
        }

        if(pos != -1) {
            x += X[pos] - X[p];
            y += Y[pos] - Y[p];
            t = (t + pos - p) % mod;
            p = pos;
            if(s[p] == 'U') {
                lenr--; ans = (ans + 1ll*t*lenc) % mod;
                x = 0;
            } else if(s[p] == 'D') {
                lenr--; ans = (ans + 1ll*t*lenc) % mod;
            } else if(s[p] == 'L') {
                lenc--; ans = (ans + 1ll*t*lenr) % mod;
                y = 0;
            } else {
                lenc--; ans = (ans + 1ll*t*lenr) % mod;
            }
            if(p == k) p = 0;
        } else {
            x += X[k] - X[p];
            y += Y[k] - Y[p];
            t = (t + k - p) % mod;
            p = 0;
        }

    }
    printf("%lld\n", ans);
    return 0;
}

/*
*/

 

转载于:https://www.cnblogs.com/CJLHY/p/9733899.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值