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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

小G的项链(Manacher)

發布時間:2023/12/3 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 小G的项链(Manacher) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

我看網上也沒有寫這個題的,順便寫一下(可能是大佬都覺得太簡單了 )
鏈接:牛客網

時間限制:C/C++ 1秒,其他語言2秒 空間限制:C/C++ 32768K,其他語言65536K 64bit IO Format:
%lld

題目描述

有一串有n顆珠子的項鏈,每顆珠子上有一個數字,從順時針方向看依次是第1,2,…,n個珠子,第n個珠子之后是第1個珠子。但是小G覺得這串項鏈的造型不夠美觀,他決定用這串項鏈上的珠子造出一個新的項鏈,并且他希望這串新的項鏈是對稱的。
一串項鏈是對稱的,當且僅當存在至少一顆珠子滿足:把它作為起始位置(即順時針和逆時針方向數第0個珠子),對于任意的自然數i,順時針數第i個珠子上的數字和逆時針數第i個珠子上的數字相同。特別的,一個僅有一顆珠子的項鏈也是對稱的。
小G可以使用合成技術將任意正整數顆珠子合成為一個新的珠子,新珠子上的數字=原珠子上的數字的異或和。
用合成技術造出新項鏈的過程是這樣的:最開始由小G確定一個能整除n的正整數k和一個原項鏈中的起始位置,之后從起始位置開始順時針方向取連續的k個珠子,合成一個新的珠子作為新項鏈的第1個珠子,再取接下來連續的k個珠子,合成一個新的珠子作為新項鏈的第2個珠子,……,直到取完原項鏈的所有珠子為止。注意,合成的新珠子會直接放到新項鏈的位置,并不會插入原項鏈之中參與之后合成過程。新項鏈同樣滿足從順時針方向看依次是第1,2,…,n個珠子,第n個珠子之后是第1個珠子。
小G希望新的項鏈上的珠子盡可能多,問新項鏈上的珠子最多有多少個。

輸入描述:

第一行一個整數n。
第二行n個整數,第i個整數ai代表原項鏈上第i個珠子上的數字。

輸出描述:
共一行一個整數,代表新項鏈的最大珠子數量。
示例1
輸入

5 9 3 9 1 1

輸出

5

示例2
輸入

9 7 8 6 5 4 3 1 2 15

輸出

3

備注:
1 ≤ n ≤ 2 x 105,0 ≤ ai ≤ 109
題意:
給你n個數組成環,分成k個等長的區間,每個區間的值就是區間內部數的異或和,用區間的相對位置擺成環,且使這個環組成回文串,問你回文串最長是多少?
題解:
因為n個數組成環,所以我們先把環破開,就是環翻倍(n+n),讓尾連頭。然后求出所有前綴異或和pre
因為要把n分成長度為len的num個區間。
我們要嘗試len的每一種情況,讓每個區間內的len個數異或和,然后看組成的是不是回文串,找到最大的len情況。
因為我們一開始將2*n個數都存了前綴異或和,根據異或的性質,a^a=0,所以我就可以通過前綴異或和輕松算出每個區間的異或值(比如pre[3] ^ pre[6]算出來就是區間[4,6]的異或和,因為3之前的重復就消除了)
求出每區間的異或和放在一個數組b中,再求b是否為回文串。但注意b是一個環直接判斷可能不對(比如abb不是回文串,但是abb是一個環如果你用正確的打開方式,它也可以是bab,那就是回文串了),那該怎么辦?對,既然是環我們就給它拆成鏈,我們把項鏈倍長,如果倍長后的字符串中存在一個子串是回文串且長度超過了倍長前字符串的長度,顯然是存在對稱軸的。
(還是abb,拆之后就是abbabb,看這個最長回文串的長度(5)是否大于本身(3))
至此基本上就大功告成了
什么?你說用什么求回文串,(那肯定暴力 )當然用Manacher
b站講解Manacher
附碼:

#include <bits/stdc++.h> using namespace std; const int maxn = 1e6 + 5;int n; int p[maxn*2]; int str[maxn*2];//數組范圍要乘2,因為環要拆成鏈 int a[maxn*2]; int b[maxn*2]; int pre[maxn*2];int init(int *s,int len) {str[0]='@';int ant=1;str[1]='#';for(int i=1;i<=len;i++){str[++ant]=s[i];str[++ant]='#';}str[++ant]='\0';return ant; } int manacher(int *s,int num) {int ans=-1;int len=init(b,num);int mx=0;int id=0;for(int i=1;i<len;i++){if(i<mx)p[i]=min(p[id*2-i],mx-i);else p[i]=1;while(str[i+p[i]]==str[i-p[i]])p[i]++;if(p[i]+i>mx)mx=p[i]+i,id=i;ans=max(ans,p[i]-1);}return ans; } bool check(int len) {int num = n / len;for(int i = 0; i < len; i++) {for(int j = 0; j < num; j++) {b[j] = pre[(j + 1) * len + i] ^ pre[j * len + i];}for(int i = 0; i < num; ++i) {b[i + num] = b[i];}if(manacher(b, num * 2)>num) return true;}return false; } int main() {cin>>n;for(int i = 1; i <= n; i++) {cin>>a[i];pre[i] = pre[i-1] ^ a[i];}for(int i = n + 1; i <= n + n; i++) {pre[i] = pre[i - 1] ^ a[i - n];}int ans = 1;for(int i = 1; i <= sqrt(n); i++) {if(n % i) continue;if(check(n / i)) ans = max(ans, i);if(check(i)) ans = max(ans, n / i);}printf("%d\n", ans);return 0; }

總結

以上是生活随笔為你收集整理的小G的项链(Manacher)的全部內容,希望文章能夠幫你解決所遇到的問題。

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