4866: [Ynoi2017]由乃的商場之旅

4866: [Ynoi2017]由乃的商場之旅

Time Limit: 20 Sec Memory Limit: 164 MB
Submit: 192 Solved: 47
[Submit][Status][Discuss]
Description

由乃有一天去參加一個商場舉辦的遊戲。商場派了一些球王排成一行。每個人面前有幾堆球。說來也巧,由乃和你
一樣,覺得這遊戲很無聊,於是決定換一個商場。另一個商場是Deus的,他看到由乃來了,於是想出了一個更有趣
的遊戲:寫數據結構題這個題是這樣的:
我們的情人,不過是隨便借個名字,用幻想吹出來的肥皂泡,把信拿去吧,你可以使假戲成真。我本來是無病呻吟
,漫無目的的吐露愛情—現在這些漂泊不定的鳥兒有地方棲息了,你可以從信裏看出來。拿去吧—由於不是出自
真心,話就說得格外動聽,拿去吧,就這麼辦吧…由於世界會在7月20日完結,作爲救世主,間宮卓司要在19日讓
所有人迴歸天空現在已經是19日傍晚,大家集合在C棟的天台上,一共n個人在他們面前,便是終之空,那終結的天

迴歸天空是一件莊重的事情,所以卓司決定讓大家分批次進行,給每個人給了一個小寫字母’a’->’z’作爲編號一個
區間的人如果滿足他們的編號重排之後可以成爲一個迴文串,則他們可以一起迴歸天空,即這個區間可以迴歸天空
由於卓司是一個喜歡妄想的人,他妄想了m個區間,每次他想知道每個區間中有多少個子區間可以迴歸天空因爲世
界末日要來了,所以卓司的信徒很多
由乃天天做數據結構已經快噁心死了,於是讓您幫她做當然,您天天做數據結構題,肯定也覺得噁心死了,不過可
愛即正義!所以這個題還是要做的~
Input

第一行兩個數n,m
之後一行一個長爲n的字符串,代表每個人的編號
之後m行每行兩個數l,r代表每次卓司妄想的區間
n,m<=60000
Output

m行,每行一個數表示答案
Sample Input

6 6

zzqzzq

1 6

2 4

3 4

2 3

4 5

1 1
Sample Output

16

4

2

2

3

1
HINT

Source

By 佚名提供

對於字母a ,賦予權值1 ,對於字母b ,賦予權值2 ,對於字母c ,賦予權值4
那麼對於原串的任意一段子區間,取G 爲區間內權值的xor
這個子區間能重新排列成一個迴文串,當且僅當G=0G2 的冪次
用前綴後綴的思路瞎搞搞,能想出一個單次添加或刪除頭或尾O(26) 的算法
結合莫隊算法能搞出一個O(26nn) 的算法
然而無論怎麼卡常數,這個算法就是過不去。。。。。
沒有辦法的,理論複雜度太差了!
下面結合平衡規劃的思路,給出一個O(n26n) 的算法
pre[i] 爲位置i 的前綴xor
那麼任意兩個pre 值的xor 結果就能表示原串中一個子區間的信息
cnt[x] 爲當新增一個值爲pre[x] 的端點時新增的合法區間個數
那麼新增端點時可以O(26) 更新好cnt
B=26n ,對於原串,每B 個字符分一塊
對於每個位置i ,記sum[i] 爲位置i 到它所在塊的右端點這個區間中的合法區間個數
那麼對於所有長度大於B 的詢問,它的答案分三類統計

這裏寫圖片描述

圖中p 爲左端點L 所在塊的右端點
對於[L,p] 內部的貢獻已經預處理好了
對於[p+1,R] 的貢獻可以通過莫隊算法修改的時候統計好
對於橫跨兩段的貢獻,枚舉每個[L1,p1]pre 值,直接用當前的cnt 即可
於是對於所有長度大於B 的詢問可以用總的O(n26n) 解決
對於那些長度不超過B 的詢問,從左往右O(26n) 更新cnt 數組
在過程中利用類似上面那個辦法減掉不存在的貢獻即可

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<cmath>
#include<algorithm>
using namespace std;

const int M = 50;
const int N = 1 << 26;
const int maxn = 6E4 + 6;
typedef unsigned int u32;
typedef unsigned short u16;

struct data{
    int l,r,Num; data(){}
    data(int l,int r,int Num): l(l),r(r),Num(Num){}
    bool operator < (const data &B) const {return r < B.r;}
};

int n,m,tot,B,pre[maxn],bel[maxn],L[M],R[M],mi[30];
u16 cnt[N]; u32 sum[maxn],Ans[maxn];

vector <data> v[M],F[maxn],G[maxn];

inline void Add(int x) {for (int i = 0; i <= 26; i++) ++cnt[x ^ mi[i]];}
inline void Del(int x) {for (int i = 0; i <= 26; i++) --cnt[x ^ mi[i]];}

inline int getint()
{
    char ch = getchar(); int ret = 0;
    while (ch < '0' || '9' < ch) ch = getchar();
    while ('0' <= ch && ch <= '9')
        ret = ret * 10 + ch - '0',ch = getchar();
    return ret;
}

inline int Get()
{
    char ch = getchar();
    while (ch < 'a' || 'z' < ch) ch = getchar();
    return 1 << ch - 'a';
}

char s[20];
inline void Print(u32 x)
{
    if (!x) {puts("0"); return;} int len = 0;
    while (x) s[++len] = x % 10,x /= 10;
    for (int i = len; i; i--) putchar(s[i] + '0'); puts("");
}

void Solve1()
{
    u32 now = 0; Add(pre[0]);
    for (int i = 1; i <= n; i++)
    {
        now += cnt[pre[i]];
        for (int j = 0; j < F[i].size(); j++)
            Ans[F[i][j].Num] += now;
        for (int j = 0; j < G[i].size(); j++)
        {
            data d = G[i][j];
            for (int k = d.l; k <= d.r; k++)
                Ans[d.Num] -= cnt[pre[k]];
            Ans[d.Num] -= now;
        }
        Add(pre[i]);
    }
    for (int i = 0; i <= n; i++) Del(pre[i]);
}

void Solve2()
{
    for (int i = 1; i <= tot; i++)
    {
        if (!v[i].size()) continue;
        sort(v[i].begin(),v[i].end());
        int r = R[i]; u32 now = 0; Add(pre[R[i]]);
        for (int j = 0; j < v[i].size(); j++)
        {
            data d = v[i][j];
            while (r < d.r) now += cnt[pre[++r]],Add(pre[r]);
            Ans[d.Num] = now + sum[d.l]; Del(pre[R[i]]);
            for (int j = d.l - 1; j < R[i]; j++)
                Ans[d.Num] += cnt[pre[j]]; Add(pre[R[i]]);
        }
        for (int j = R[i]; j <= r; j++) Del(pre[j]);
    }
}

void Pre_Work()
{
    mi[0] = 1; for (int i = 1; i < 26; i++) mi[i] = mi[i - 1] << 1;
    for (int i = 1; i <= n; i++)
        pre[i] = pre[i - 1] ^ Get(),bel[i] = (i - 1) / B + 1;
    for (int i = 1; i <= bel[n]; i++)
        L[i] = R[i - 1] + 1,R[i] = i * B;
    tot = bel[n]; R[tot] = n;
    for (int i = 1; i <= tot; i++)
    {
        for (int j = R[i] - 1; j >= L[i] - 1; j--)
            Add(pre[j + 1]),sum[j + 1] = sum[j + 2] + cnt[pre[j]];
        for (int j = R[i]; j >= L[i]; j--) Del(pre[j]);
    }
    for (int i = 1; i <= m; i++)
    {
        int l = getint(),r = getint();
        if (bel[l] == bel[r])
        {
            F[r].push_back(data(l,r,i));
            G[l - 1].push_back(data(l,r,i));
        }
        else v[bel[l]].push_back(data(l,r,i));
    }
}

int main()
{
    #ifdef DMC
        freopen("DMC.txt","r",stdin);
    #endif

    n = getint(); m = getint();
    B = sqrt(26 * n); Pre_Work();
    Solve1(); Solve2();
    for (int i = 1; i <= m; i++) Print(Ans[i]);
    return 0;
}
發佈了730 篇原創文章 · 獲贊 20 · 訪問量 30萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章