日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【倍增】7.11fusion

發布時間:2024/6/30 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【倍增】7.11fusion 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

非常奇妙的倍增題

題目描述

知名科學家小A在2118年在計算機上實現了模擬聚變的過程。我們將她研究的過程簡化。核子共有26種,可以用a到z共26個字母表示。核子聚變的過程可以用一個字符串描述。按照順序從左到右的順序,假如有兩個相同核子相鄰,兩個核子就會相互吸引發生聚變生成一個序號+1的核子,特殊的,兩個z核子相鄰會湮滅沒有新的核子生成。每當兩個核子聚變時,就需要重新從左到右重復找到兩個相鄰的相同核子直到不存在為止。比如zyzzy->zyy->zz->小A為了做出足夠有效的實驗,每次會從一個字符串中選定一個子串操作。她想要知道每次實驗這個子串中的核子能否最終全部湮滅。

輸入格式

第一行一個只有小寫字母的字符串。第二行一個數nn表示詢問次數接下來nn行每行兩個正整數li,rili,ri表示詢問區間

輸出格式

對每次詢問輸出一行Yes或No表示答案

樣例輸入

yzyyyzyzyyyz

8

1 6

7 12

1 12

6 11

1 1

1 3

4 9

3 8

樣例輸出

Yes

Yes

Yes

Yes

No

No

No

No

數據規模與約定

L表示字符串長度對于30%的數據滿足L<=100

對于60%的數據滿足L<=3000,n<=3000

另存在20%數據滿足字符串中只存在y,z

對于100%的數據,L<=500000,n<=1000000


題目分析

摘要

第一眼看上去是個數據結構題……但是很明顯這題的狀態數非常多,并且區間信息也難以合并,所以所有基于序列長度的維護都是要掛的。

這題妙就是在于它用倍增維護基于結果的區間信息。(聽上去很高端的樣子實際上是不難理解的)

暴力做法

暴力的O(n^2)做法可以得60pts。具體實現可以用棧也可以用鏈表。

大概就是這個樣子。

?

1 #include<bits/stdc++.h> 2 const int maxn = 8000035; 3 const long long numz = 33554432; 4 5 long long f[maxn]; 6 int pre[maxn],nxt[maxn],head,tail; 7 char ch[maxn]; 8 int n,m,a[maxn],tot; 9 10 int lowbit(int x){return x&-x;} 11 void add(int x, long long c){for (; x<=n; x+=lowbit(x)) f[x]+=c;} 12 long long query(int x) 13 { 14 long long ret = 0; 15 for (; x; x-=lowbit(x)) ret += f[x]; 16 return ret; 17 } 18 bool check(int l, int r) 19 { 20 tot = n, head = l, tail = r; 21 for (int i=l; i<=r; i++) 22 pre[i] = i-1, nxt[i] = i+1; 23 pre[l] = -1, nxt[r] = -1; 24 for (;;) 25 { 26 bool fl = 0; 27 if (head==-1) return 1; 28 if (nxt[head]==-1) return 0; 29 for (int now=head; nxt[now]!=-1; now=nxt[now]) 30 if (a[now]==a[nxt[now]]){ 31 fl = 1; 32 if (a[now]==numz){ 33 int ss = pre[now], tt = nxt[nxt[now]]; 34 if (head==now){ 35 head = tt; 36 if (tt==-1) return 1; 37 pre[tt] = -1; 38 } 39 else{ 40 nxt[ss] = tt; 41 if (tt!=-1) pre[tt] = ss; 42 } 43 }else{ 44 a[++tot] = a[now]*2; 45 int ss = pre[now], tt = nxt[nxt[now]]; 46 if (head==now){ 47 head = tot; 48 if (tt==-1) return 0; 49 pre[tt] = tot, nxt[tot] = tt; 50 } 51 else{ 52 nxt[ss] = tot, pre[tot] = ss, nxt[tot] = tt; 53 if (tt!=-1) pre[tt] = tot; 54 } 55 } 56 break; 57 } 58 if (!fl) return 0; 59 } 60 } 61 int main() 62 { 63 freopen("fusion.in","r",stdin); 64 freopen("fusion.out","w",stdout); 65 scanf("%s",ch+1); 66 n = strlen(ch+1); 67 for (int i=1; i<=n; i++) 68 a[i] = 1<<(ch[i]-'a'), add(i, 1ll*a[i]); 69 scanf("%d",&m); 70 for (int i=1; i<=m; i++) 71 { 72 int l,r; 73 scanf("%d%d",&l,&r); 74 if ((query(r)-query(l-1))%numz==0){ 75 if (check(l, r)) puts("Yes"); 76 else puts("No"); 77 }else puts("No"); 78 } 79 return 0; 80 } 鏈表模擬

?

?

?

?

跳一跳?

用nxt[i]表示以i為左端點第一次消完的區間右端點。那么只要預處理出這個nxt[]就可以做到快速查詢了————然而查詢時也有可能被例如zzzzzzzzz...的數據卡飛,不過對于隨機數據已經做得夠好了。

先不管zzzzz...的情況,來考慮如何處理nxt[]。

用$t_{i,char}$表示i位置往后第一次遇到char字符的位置,這個是用來處理“聚變”的過程。那么顯然這個可以用倍增維護。

處理出$t_{i,char}$之后,nxt[i]就等于$t_{i,z+1}$,這里我們把z聚變后也看做一個虛擬的字符。

再來一個倍增!

既然一維的$nxt[]$會被卡掛,那么同時處理消去好幾次后的$nxt[]$(等同于跳了多次)呢?那么nxt[i][j]就表示以i開頭消去j次后的位置。

重要的細節

這里有一組數據:xzzxyz

如果只有上面的操作,答案將會是No,因為計算出的結果里第一個x與第二個x是不能接觸的。

所以要根據算出的$t_{i,z+1}$更新所有的$t_{i,j}$

?

1 #include<bits/stdc++.h> 2 #pragma GCC optimize(2) 3 const int maxn = 500035; 4 const int maxLog = 19; 5 const long long numz = 33554432; 6 7 int n,m,s[maxn]; 8 int t[maxn][28],nxt[maxn][20]; 9 char ch[maxn]; 10 11 bool check(int l, int r) 12 { 13 for (int i=maxLog; i>=0; i--) 14 if (nxt[l][i]==r+1) return 1; 15 else if (nxt[l][i]<=r) l = nxt[l][i]; 16 return 0; 17 } 18 void init() 19 { 20 register int i,j; 21 for (i=0; i<=n+2; i++) 22 { 23 for (j=0; j<=26; j++) t[i][j] = n+2; 24 for (j=0; j<=maxLog; j++) nxt[i][j] = n+2; 25 } 26 for (i=n; i>=1; i--) 27 { 28 t[i][s[i]] = i+1; 29 for (j=s[i]+1; j<=26; j++) t[i][j] = t[t[i][j-1]][j-1]; 30 nxt[i][0] = t[i][26]; 31 for (j=0; j<=26; j++) 32 if (t[i][j]==n+2) 33 t[i][j] = t[nxt[i][0]][j]; 34 for (j=1; j<=maxLog; j++) nxt[i][j] = nxt[nxt[i][j-1]][j-1]; 35 } 36 } 37 int main() 38 { 39 register int i,l,r; 40 freopen("fusion.in","r",stdin); 41 freopen("fusion.out","w",stdout); 42 scanf("%s",ch+1); 43 n = strlen(ch+1); 44 for (i=1; i<=n; i++) s[i] = ch[i]-'a'; 45 scanf("%d",&m); 46 init(); 47 for (i=1; i<=m; i++) 48 { 49 scanf("%d%d",&l,&r); 50 if (check(l, r)) puts("Yes"); 51 else puts("No"); 52 } 53 return 0; 54 }

?

?

?

END

?

轉載于:https://www.cnblogs.com/antiquality/p/9296735.html

總結

以上是生活随笔為你收集整理的【倍增】7.11fusion的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。