COCI2014/2015 Contest#1 PIRAMIDA 優化空間

src 給1e6長的字符串,構造一個連續排列的金字塔,類似蛇形地放入。求第ai行字符ci有幾個。ai有1e18,但詢問k只有1e5。


對單個詢問,容易想到求前後綴。因爲第ai行之前的長度,能用求和公式算出來,雖然溢出longlong,但我們只需要取模能知道ai開始和結尾的信息即可。

這道題內存只給 65536K(65MB),特意去卡 1e6*26的二維數組。(int數組這樣開接近100MB),只好用一維數組。我把詢問離線存下,按字母排序,每次字母改變時,重新計算前後綴。

注意,求和公式的時候,涉及1e18數量級的乘法。最好每個數都保證在模範圍內。

#pragma comment(linker, "/STACK:102400000,102400000")
#define _debug(x) cerr<<#x<<" = "<<(x)<<endl;fflush(stdout)

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
const int MAXN = 1e6 + 77;
const ll INF = 0x3f3f3f3f;
const ll MOD = 1e9 + 7;

struct Query {
    ll ai;
    char ci;
    int i;

    bool operator<(const Query &q) const {
        return ci < q.ci;
    }

} ask[50004];


ll n, k;
ll ans[50004];
int ser[MAXN];
int pre[MAXN];
char s[MAXN];

char ch[2];
char ci;
char lci = -1;

ll ai;
ll rlen, plen, timz, tlen, slen;

inline void recalc(char c) {
    for (ll i = 1, j = slen; i <= slen; ++i, --j) {
        pre[i] = pre[i - 1];
        ser[i] = ser[i - 1];
        if (s[i] == c)pre[i]++;
        if (s[j] == c)ser[i]++;
    }
}

int main() {
//    ios::sync_with_stdio(false);
//    cin.tie(nullptr);
    scanf("%lld %s", &n, s + 1);
    scanf("%lld", &k);

    slen = strlen(s + 1);

    for (int i = 0; i < k; ++i) {
        scanf("%lld %s", &ai, ch);
        ci = ch[0] - 'A';
        ask[i] = {ai, ci, i};
    }
    sort(ask, ask + k);

    for (int id, i = 0; i < k; i++) {
        ai = ask[i].ai;
        ci = ask[i].ci;
        id = ask[i].i;

        if (lci != ci)
            recalc(ci + 'A');
        lci = ci;

        if (ai % 2 == 0) {
            rlen = (((ai - 1) % slen) * ((ai / 2ll) % slen)) % slen;
        } else {
            rlen = ((((ai - 1) / 2ll) % slen) * (ai % slen)) % slen;
        }
        // rest  before the ai line

        plen = (slen - rlen);
        if (ai <= plen) {
            ans[id] = ser[plen] - ser[plen - ai];
            continue;
        }
        timz = (ai - plen) / slen;
        tlen = (ai - plen) % slen;
        ans[id] = ser[plen] * 1ll + timz * pre[slen] + pre[tlen] * 1ll;
    }
    for (int i = 0; i < k; i++) {
        printf("%lld\n", ans[i]);
    }

    return 0;
}

/*

8000000000000
JANJETINA
5
6000000000001 J
6000000000002 A
6000000000003 N
6000000000004 N
6000000000005 N

8000000000000
AB
10
60000000000000001 A
60000000000000001 B
60000000000000002 A
60000000000000002 B
60000000000000003 A
60000000000000003 B
60000000000000004 A
60000000000000004 B
60000000000000005 A
60000000000000005 B

8000000000000
AB
10
1 A
1 B
2 A
2 B
3 A
3 B
4 A
4 B
5 A
5 B

8000000000000
AB
5
60000000000000000 A
60000000000000001 A
60000000000000002 A
60000000000000003 A
60000000000000004 A
 * */
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章