HDU-6387 AraBellaC(RMQ)

AraBellaC

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 101    Accepted Submission(s): 41

Problem Description

Princess Arabella loves the letter `C`, which earned her the epithet `ArraBellaC`. She would like to endeavor to construct a periodic string with length n(n≤20000)to spare her tedious time. In every period of the string, the substring begins with dozens of `A`s and ends with dozens of `C`s, and dozens of `B`s are inserted between them, and the number of `A`, `B`, `C` is a, b, c.(For example, if a=1, b=1, c=2 then one of the period of the string is `ABCC`, and the periodic string is `ABCCABCC……`).Note that in the last period of the string, the substring can be incomplete and the last few letters of the period can be cut down.

And now, Arabella has constructed a periodic string, she want to give you a question: if she tells you the character is Ci(Ci∈{A,B,C}) in the Xi(Xi≤10000) , then could you tell her the value of a,b,c? If there are multiple answers, please find the lexicographically smallest answer. If you can’t find a valid answer, please print `NO`

Input

The first line gives an integer T(1≤T≤40) , which indicates the number of cases in the input.
The first line of every case contains only one integer m(1≤m≤5000), which means the number of characters AraBella told you.
A number Xi(1≤Xi≤10000) and a letter Ci are given in the following m lines, which means the position Xi in the string with letter Ci. 

Output

Print a,b,c in order. If there are multiple answers, please find the lexicographically smallest answer. If you can’t find a valid answer, please print `NO`.(It is gratuated that 0<a,b,c, and please forget my poor Yinglish)

Sample Input

2 3 1 A 2 B 3 C 4 1 A 2 C 3 B 4 C

Sample Output

1 1 1 NO

题意:一个无限长的字符串,由一个叫periodic string的子串重复出现得到,如:子串为ABCC,则无限长字符串为ABCCABCC...。定义a b c为periodic string中ABC的数量。

现在给出m个字符出现的位置,问合法的情况下,字典序最小的a b c是多少,若没有合法情况,则输出NO。

题解:由于总长度只有1e4,可以枚举重复子串的长度,复杂度为O(nlogn),对于每个子串看做一块,每块内分别维护ABC的最左最右端点,根据题意可以知道,ABC的区间不能相交,否则就是不合法的,维护可以用RMQ。最后维护答案,选择abc字典序较小的即可。

#include <bits/stdc++.h>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define x first
#define y second
#define rep(i,a,b) for(int i=a;i<b;++i)
#define per(i,a,b) for(int i=a-1;i>=b;--i)
#define fuck(x) cout<<'['<<#x<<' '<<(x)<<']'
#define eps 1e-8
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef vector<int> VI;
typedef pair<int, int> PII;

const int INF = 0x3f3f3f3f;
const ll INFLL = 0x3f3f3f3f3f3f3f3fll;
const int MX = 1e4 + 5;
const int MM = 30;

int A[MX][MM], Bl[MX][MM], Br[MX][MM], C[MX][MM];
char ch[MX];

void ST(int n) {
    rep(i, 0, n) {
        A[i][0] = 0, Bl[i][0] = 2 * n, Br[i][0] = 0, C[i][0] = 2 * n;
        if(ch[i] == 'A') A[i][0] = i;
        if(ch[i] == 'B') Bl[i][0] = Br[i][0] = i;
        if(ch[i] == 'C') C[i][0] = i;
    }
    for(int j = 1; (1 << j) <= n; j++) {
        for(int i = 0; i + (1 << j) - 1 < n; i++) {
            A[i][j] = max(A[i][j - 1], A[i + (1 << (j - 1))][j - 1]);
            C[i][j] = min(C[i][j - 1], C[i + (1 << (j - 1))][j - 1]);
            Bl[i][j] = min(Bl[i][j - 1], Bl[i + (1 << (j - 1))][j - 1]);
            Br[i][j] = max(Br[i][j - 1], Br[i + (1 << (j - 1))][j - 1]);
        }
    }
}
int n;
int RMQ_min(int dp[][MM], int l, int r) {
    int k = 0;
    assert(0 <= l && l <= r && r < n);
    while((1 << (k + 1)) <= r - l + 1) k++;
    assert(r - (1 << k) + 1 >= 0);
    return min(dp[l][k], dp[r - (1 << k) + 1][k]);
}
int RMQ_max(int dp[][MM], int l, int r) {
    int k = 0;
    assert(0 <= l && l <= r && r < n);
    while((1 << (k + 1)) <= r - l + 1) k++;
    assert(r - (1 << k) + 1 >= 0);
    return max(dp[l][k], dp[r - (1 << k) + 1][k]);
}

bool check(int L1, int R1, int L2, int R2) {
    return (L1 <= L2 && R1 >= L2) || (L1 <= R2 && R1 >= R2) || (L2 <= L1 && R2 >= L1) || (L2 <= R1 && R2 >= R1);
}
int vis[MX];
int main() {
#ifdef local
    freopen("in.txt", "r", stdin);
#endif // local
    char op[2];
    int T, m; cin >> T;
    while(T--) {
        scanf("%d", &m);
        int ans = 1, x; n = 0;
        memset(vis, 0, sizeof(vis));
        memset(ch, 0, sizeof(ch));
        rep(i, 0, m) {
            scanf("%d %s", &x, op);
            assert(x > 0 && x <= 10000);
            ch[--x] = op[0]; n = max(n, x + 1);
            if(vis[x] && vis[x] != op[0]) ans = 0;
            vis[x] = op[0];
        }
        ST(n);
        int a = n + 1, b = n + 1, c = n + 1, mark = 0;
        for(int N = 1; N <= n + 1; N++) {
            int LA = 0, RA = 0, LB = n, RB = 0, LC = n, RC = N - 1;
            for(int i = 0; i < n; i += N) {
                int l = i, r = min(i + N - 1, n - 1);
                RA = max(RA, RMQ_max(A, l, r) - l);
                LC = min(LC, RMQ_min(C, l, r) - l);
                LB = min(LB, RMQ_min(Bl, l, r) - l);
                RB = max(RB, RMQ_max(Br, l, r) - l);
            }
            int flag = 1, cnt1 = 0, cnt2 = 0, cnt3 = 0;
            if(check(LA, RA, LC, RC)) flag = 0;
            if(LB <= RB && check(LA, RA, LB, RB)) flag = 0;
            if(LB <= RB && check(LB, RB, LC, RC)) flag = 0;
            cnt1 = max(cnt1, RA - LA + 1);
            if(LB <= RB) {
                cnt2 = max(cnt2, RB - RA);
                cnt3 = max(cnt3, RC - RB);
            } else {
                cnt3 = max(cnt3, RC - RA);
            }
            if(flag) {
                mark = 1;
                if(a > cnt1) a = cnt1, b = cnt2, c = cnt3;
                else if(a == cnt1 && b > cnt2) b = cnt2, c = cnt3;
                else if(a == cnt1 && b == cnt2 && c > cnt3) c = cnt3;
            }
        }
        if(!mark) printf("NO\n");
        else printf("%d %d %d\n", a, b, c);
    }
#ifdef local
    cout << "time cost:" << clock() << "ms" << endl;
#endif // local
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值