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=0 或G 爲2 的冪次
用前綴後綴的思路瞎搞搞,能想出一個單次添加或刪除頭或尾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] 的貢獻可以通過莫隊算法修改的時候統計好
對於橫跨兩段的貢獻,枚舉每個[L−1,p−1] 的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;
}