NOI 2016 優秀的拆分 (后綴數組+差分)

題目大意:給你一個字符串,求所有子串的所有優秀拆分總和,優秀的拆分被定義為一個字符串可以被拆分成4個子串,形如$AABB$,其中$AA$相同,$BB$相同,$AB$也可以相同

作為一道國賽題,95分竟然就這么給我們了!只是一個$NOIP$難度的哈希套$DP$啊......

95分就是從后往前找,統計$AA$串,每次統計一下從這個位置開始的所有子串 和 緊隨其后的等長串 相同的個數$sum$

$hash(i,i+j-1)==hash(i+j,i+2*j-1) sum[i]++$

然后再統計$BB$串,就是加上在這兩個串之后的位置的$sum$值,這樣就統計出了合法拆分數

$dp[i]+=sum[i+2*j]$

95分就這樣到手啦,竟然連自然溢出hash都不卡

 1 #include <cmath>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 #define ll long long 
 6 #define ull unsigned long long 
 7 #define N 2050
 8 #define seed 233
 9 #define idx(x) (x-'a'+1)
10 using namespace std;
11 //re
12 int T,len;
13 char str[N];
14 int dp[N],sum[N];
15 ull hsh[N],sp[N];
16 ull ghsh(int x,int y) {return hsh[y]-hsh[x-1]*sp[y-x+1];}
17 void clr()
18 {
19     memset(dp,0,sizeof(dp));
20     memset(sp,0,sizeof(sp));
21     memset(sum,0,sizeof(sum));
22     memset(hsh,0,sizeof(hsh));
23 }
24 int main()
25 {
26     scanf("%d",&T);
27     while(T--)
28     {
29         clr();
30         scanf("%s",str+1);
31         len=strlen(str+1);
32         sp[0]=1;
33         for(int i=1;i<=len;i++)
34             hsh[i]=hsh[i-1]*seed+idx(str[i]),
35             sp[i]=sp[i-1]*seed;
36         for(int i=len-1;i>=1;i--)
37         {
38             for(int j=1;i+2*j-1<=len;j++)
39             {
40                 if(ghsh(i,i+j-1)==ghsh(i+j,i+2*j-1)){
41                     dp[i]++;
42                     sum[i]+=dp[i+2*j];
43                 }
44             }
45         }
46         int ans=0;
47         for(int i=1;i<=len;i++)
48             ans+=sum[i];
49         printf("%d\n",ans);
50     }
51     return 0;
52 }

接下來才是本題的重點!$NOI$豈是你想$AK$就$AK$的!出題人可能是想針對某位巨佬

不看題解這個正解思路真是很難想到......

思路大概是這樣的,其實我們每次只需要統計$AA$串的數量就行了,因為$AABB$串的數量等于,在$i-1$位結束的$AA$串的數量乘以在第$i$位開始的$AA$串的數量,用公式表示就是

\sum_{i=2}^{n} ed[i-1]*st[i]

接下來就是統計$st$和$ed$了,感覺正解的思路很神

先用后綴數組+$ST$表處理出任意兩個位置,作為后綴串開頭的$LCP$以及作為前綴串末尾的$LCS$,求$LCS$可以把串反著讀再去套$SA$

每次選取一個$A$串的長度$len$,再在原串每隔$len$的位置設一個關鍵點

然后會發現一個神奇的性質,任意一個長度為$2*len$的串必然經過且僅經過2個關鍵點!

接下來統計經過所有長度為$2*len$所有$AA$串,比如選定兩個關鍵點$a,b$,且$a+len=b$

如果把$a$的和b$相同的前綴和后綴拼在一起,且拼完之后長度>=len,說明存在至少一個$AA$串

可以把$AA$串想象成一個塊,在兩個關鍵點上移動,塊的左端點不能大于$a$,塊的右端點不能小于$b$,塊不能移動到上一個或者下一個關鍵點的位置,塊內必須是$AA$串,這樣,塊所有能移動的位置-塊的長度$len$,就是經過$ab$兩個關鍵點的所有$AA$串數

時間變成O(nlogn),$logn$是調和級數的近似值

細節比較多需要仔細思考

  1 #include <cmath>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <algorithm>
  5 #define ll long long 
  6 #define N 30100
  7 #define seed 233
  8 #define idx(x) (x-'a'+1)
  9 using namespace std;
 10 //re
 11 int T,len;
 12 int lg[N];
 13 ll st[N],ed[N],S[N],E[N];
 14 struct suffix{
 15     char str[N];
 16     int sa[N],tr[N],rk[N],hs[N],h[N],f[N][15],len; 
 17     bool check(int k,int x,int y){
 18         if(x+k>len||y+k>len) return 0;
 19         else return (rk[x]==rk[y]&&rk[x+k]==rk[y+k])?1:0;
 20     }
 21     void get_suffix()
 22     {
 23         int cnt=0,i;len=strlen(str+1);
 24         for(i=1;i<=len;i++) hs[str[i]]++;
 25         for(i=1;i<=127;i++) if(hs[i]) tr[i]=++cnt;
 26         for(i=1;i<=127;i++) hs[i]+=hs[i-1];
 27         for(i=1;i<=len;i++) rk[i]=tr[str[i]],sa[hs[str[i]]--]=i;
 28         for(int k=1;cnt<len;k<<=1)
 29         {
 30             for(i=1;i<=cnt;i++) hs[i]=0;
 31             for(i=1;i<=len;i++) hs[rk[i]]++;
 32             for(i=1;i<=cnt;i++) hs[i]+=hs[i-1];
 33             for(i=len;i>=1;i--) if(sa[i]>k) tr[sa[i]-k]=hs[rk[sa[i]-k]]--;
 34             for(i=1;i<=k;i++) tr[len-i+1]=hs[rk[len-i+1]]--;
 35             for(i=1;i<=len;i++) sa[tr[i]]=i;
 36             for(i=1,cnt=0;i<=len;i++) tr[sa[i]]=check(k,sa[i],sa[i-1])?cnt:++cnt;
 37             for(i=1;i<=len;i++) rk[i]=tr[i];
 38         }
 39         for(i=1;i<=len;i++)
 40         {
 41             if(rk[i]==1) continue;
 42             for(int j=max(1,h[rk[i-1]]-1);;j++)
 43                 if(str[i+j-1]==str[sa[rk[i]-1]+j-1]) h[rk[i]]=j;
 44                 else break;
 45         }
 46     }
 47     void get_ST()
 48     {
 49         for(int i=1;i<=len;i++) 
 50             f[i][0]=h[i];
 51         for(int k=1;(1<<k)<=len;k++)
 52             for(int i=1;i+(1<<k)-1<=len;i++)
 53                 f[i][k]=min(f[i][k-1],f[i+(1<<(k-1))][k-1]);
 54     }
 55     int query(int x,int y)
 56         {int L=y-x+1;
 57         return min(f[x][lg[L]],f[y-(1<<lg[L])+1][lg[L]]);}
 58 }p,s;
 59 void clr()
 60 {
 61     memset(S,0,sizeof(S)),memset(st,0,sizeof(st));
 62     memset(E,0,sizeof(E)),memset(ed,0,sizeof(ed));
 63     memset(&p,0,sizeof(p)),memset(&s,0,sizeof(s));
 64 }
 65 int main()
 66 {
 67     scanf("%d",&T);
 68     for(int i=2;i<=30010;i++)
 69         lg[i]=lg[i>>1]+1;
 70     while(T--)
 71     {
 72         clr();
 73         scanf("%s",s.str+1);
 74         int len=strlen(s.str+1);
 75         for(int i=1;i<=len;i++) 
 76             p.str[i]=s.str[len-i+1];
 77         s.get_suffix();
 78         s.get_ST();
 79         p.get_suffix();
 80         p.get_ST();
 81         int sx,sy,px,py,ss,sp,l,r;
 82         for(int i=1;i<=len;i++)
 83         {
 84             for(int j=i+1;j<=len;j+=i)
 85             {
 86                 sx=s.rk[j-i+1],sy=s.rk[j+1];
 87                 if(sx>sy) swap(sx,sy);
 88                 px=p.rk[len-(j-i)+1],py=p.rk[len-j+1];
 89                 if(px>py) swap(px,py);
 90                 ss=s.query(sx+1,sy);
 91                 sp=p.query(px+1,py);
 92                 if(ss+sp<i||sp==0) continue;
 93                 l=max(j-i-i+1,j-i-sp+1);
 94                 r=min(j+i-1,j+ss);
 95                 S[l]++,S[r-2*i+2]--;
 96                 E[l+2*i-1]++,E[r+1]--;
 97             }
 98         }
 99         for(int i=1;i<=len;i++)
100             st[i]=st[i-1]+S[i],ed[i]=ed[i-1]+E[i];
101         ll ans=0;
102         for(int i=2;i<=len;i++)
103             ans+=ed[i-1]*st[i];
104         printf("%lld\n",ans);
105     }
106     return 0;
107 }

?

轉載于:https://www.cnblogs.com/guapisolo/p/9707026.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/388412.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/388412.shtml
英文地址,請注明出處:http://en.pswp.cn/news/388412.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

多元線性回歸 python_Python中的多元線性回歸

多元線性回歸 pythonVideo Link影片連結 This episode expands on Implementing Simple Linear Regression In Python. We extend our simple linear regression model to include more variables.本集擴展了在Python中實現簡單線性回歸的方法 。 我們擴展了簡單的線性回歸模型…

關于apache和tomcat集群,線程是否占用實驗

測試目的&#xff1a; 測試在apache入口的時候進入&#xff0c;當Tomcat的一個請求陷入死循環&#xff0c;或者線程進入循環無反應的時候&#xff0c;是否此時占用apache的線程資源。 測試原因&#xff1a; 如果要是影響&#xff0c;無論tomcat線程設置成多大&#xff0c;都…

爬蟲之數據解析的三種方式

一&#xff0c;正則表達式解析 re正則就不寫了&#xff0c;前面已經寫入一篇很詳細的正則表達式模塊了~ 而且&#xff0c;在爬蟲中&#xff0c;下面兩種方式用的多一些~ 正則表達式&#xff1a;https://www.cnblogs.com/peng104/p/9619801.html 大致用法&#xff1a; pattern …

相對于硬件計算機軟件就是,計算機的軟件是將解決問題的方法,軟件是相對于硬件來說的...

計算機網絡管理軟件是為計算機網絡配置的系統軟件。它負責對網絡資源進行組織和管理&#xff0c;實現相互之間的通信。計算機網絡管理軟件包括網絡操作系統和數據通信處理程序。前者用于協調網絡中各計算機的操作系統及實現網絡資源的傳遞&#xff0c;后者用于網絡內的通信&…

數據冒險控制冒險_勞動生產率和其他冒險

數據冒險控制冒險Labor productivity is considered one of the most important indicators of a country’s well-being. However, we don’t know so much about it, let’s try to figure out how it is calculated, and how things are with it in the world (data source:…

如何把一個java程序打包成exe文件,運行在沒有java虛

如何把一個java程序打包成exe文件&#xff0c;運行在沒有java虛 核心提示&#xff1a;首先&#xff0c;將編譯好的程序打包成jar文件&#xff0c;然后做出exe&#xff0c;這樣代碼就不可見了&#xff1b;但是exe文件在沒有安裝jre的電腦上不能運行&#xff0c;如果要求客戶再去…

Java后端WebSocket的Tomcat實現

原文&#xff1a;https://www.cnblogs.com/xdp-gacl/p/5193279.html 一.WebSocket簡單介紹 隨著互聯網的發展&#xff0c;傳統的HTTP協議已經很難滿足Web應用日益復雜的需求了。近年來&#xff0c;隨著HTML5的誕生&#xff0c;WebSocket協議被提出&#xff0c;它實現了瀏覽器與…

加速業務交付,從 GKE 上使用 Kubernetes 和 Istio 開始

原文來源于&#xff1a;谷歌云技術博客 許多企業機構正在把全部或部分 IT 業務遷移到云端&#xff0c;幫助企業更好的運營。不過這樣的大規模遷移&#xff0c;在企業的實際操作中也有一定難度。不少企業保存在本地服務器的重要資源&#xff0c;并不支持直接遷移到云端。 另外&a…

knn 鄰居數量k的選取_選擇K個最近的鄰居

knn 鄰居數量k的選取Classification is more-or-less just a matter of figuring out to what available group something belongs.分類或多或少只是弄清楚某個事物所屬的可用組的問題。 Is Old Town Road a rap song or a country song?Old Town Road是說唱歌曲還是鄉村歌曲…

計算機網絡中 子網掩碼的算法,[網絡天地]子網掩碼快速算法(轉載)

看到一篇很好的資料&#xff0c;大家分享有很多人肯定對設定子網掩碼這個不熟悉&#xff0c;很頭疼&#xff0c;那么我現在就告訴大家一個很容易算子網掩碼的方法&#xff0c;幫助一下喜歡偷懶的人&#xff1a;)大家都應該知道2的0次方到10次方是多少把&#xff1f;也給大家說一…

EXTJS+JSP上傳文件帶進度條

需求來源是這樣的&#xff1a;上傳一個很大的excel文件到server&#xff0c; server會解析這個excel&#xff0c; 然后一條一條的插入到數據庫&#xff0c;整個過程要耗費很長時間&#xff0c;因此當用戶點擊上傳之后&#xff0c;需要顯示一個進度條&#xff0c;并且能夠根據后…

android Json詳解

Json:一種輕量級的數據交換格式&#xff0c;具有良好的可讀和便于快速編寫的特性。業內主流技術為其提供了完整的解決方案&#xff08;有點類似于正則表達式 &#xff0c;獲得了當今大部分語言的支持&#xff09;&#xff0c;從而可以在不同平臺間進行數據交換。JSON采用兼容性…

react實踐

React 最佳實踐一、 React 與 AJAXReact 只負責處理 View 這一層&#xff0c;它本身不涉及網絡請求 /AJAX: 第一&#xff0c;用什么技術從服務端獲取數據&#xff1b; 第二&#xff0c;獲取到的數據應該放在 react 組件的什么位置。 事實上是有很多的&#xff1a;fetch()、fetc…

什么樣的代碼是好代碼_什么是好代碼?

什么樣的代碼是好代碼編碼最佳實踐 (Coding Best-Practices) In the following section, I will introduce the topic at hand, giving you a sense of what this post will cover, and how each argument therein will be approached. Hopefully, this will help you decide w…

nginx比較apache

話說nginx在大壓力的環境中比apache的表現要好&#xff0c;于是下載了一個來折騰一下。 下載并編譯安裝&#xff0c;我的編譯過程有點特別&#xff1a; 1。去除調試信息&#xff0c;修改$nginx_setup_path/auto/cc/gcc這個文件&#xff0c;將 CFLAGS"$CFLAGS -g" …

計算機主板各模塊復位,電腦主板復位電路工作原理分析

電源、時鐘、復位是主板能正常工作的三大要素。主板在電源、時鐘都正常后&#xff0c;復位系統發出復位信號&#xff0c;主板各個部件在收到復位信號后&#xff0c;同步進入初始化狀態。如圖7-11所示為復位電路的工作原理圖&#xff0c;各個十板實現復位的電路不盡相同&#xf…

Docker制作dotnet core控制臺程序鏡像

(1)首先我們到某個目錄下&#xff0c;然后在此目錄下打開visual studio code. 2.編輯docker file文件如下: 3.使用dotnet new console創建控制臺程序; 4.使用docker build -t daniel/console:dev .來進行打包; 5.啟動并運行鏡像; 6.我們可以看到打包完的鏡像將近2G,因為我們使用…

【362】python 正則表達式

參考&#xff1a;正則表達式 - 廖雪峰 參考&#xff1a;Python3 正則表達式 - 菜鳥教程 參考&#xff1a;正則表達式 - 教程 re.match 嘗試從字符串的起始位置匹配一個模式&#xff0c;如果不是起始位置匹配成功的話&#xff0c;match()就返回none。 re.search 掃描整個字符串并…

在Python中使用Twitter Rest API批量搜索和下載推文

數據挖掘 &#xff0c; 編程 (Data Mining, Programming) Getting Twitter data獲取Twitter數據 Let’s use the Tweepy package in python instead of handling the Twitter API directly. The two things we will do with the package are, authorize ourselves to use the …

第一套數字電子計算機,計算機試題第一套

《計算機試題第一套》由會員分享&#xff0c;可在線閱讀&#xff0c;更多相關《計算機試題第一套(5頁珍藏版)》請在人人文庫網上搜索。1、計算機試題第一套1、計算機之所以能自動運算,就是由于采用了工作原理。A、布爾邏輯。B 儲存程序。C、數字電路。D,集成電路答案選B2、“長…