先給大家安利乙個80分(小學生都會寫的)版本
【分析】
複雜度o(n^3),在洛谷上測一下可以過80分(特判懶得寫,加上就90了…)
g[i][j] 表示i到j之間能否構成「aa」的形式,暴力就可以出來
然後枚舉子序列長度,起點位置,以及斷點位置與起點的長度,就能找出「aabb」中a與b接壤的位置,然後左邊右邊都判斷一下
【**】
//noi 2016 d1t1 優秀的拆分
#include
#include
#include
#define fo(i,j,k) for(i=j;i<=k;i++)
#define m(a) memset(a,0,sizeof a)
using
namespace
std;
bool g[2001][2001],f[2001][2001];
char c[2001];
inline
bool judge(int s,int l) //判斷哦
int main()
return0;}
//4//aabbbb
//cccccc
//aabaabaabaa
//bbaabaababaaba
現在是正解咯
求兩個陣列:st[i]與en[i],分別表示以i這個字元開頭與以i這個字元結尾的『aa』形式的串有多少個,那麼答案就是∑n−1i=1st[i+1]∗en[i],難點在於如何求出這兩個陣列:
我們列舉乙個長度l表示當前找的『aa』型串的長度的一半,列舉i=k∗l,j=i+l,
記x=lcp(i,j), 記y=lcs(i−1,j−1),
如果x+y>=l,記t=x+y−l+1,表示我們找到了t個長度為2l的』aa『串
(自己可以舉個例子看看,如』abcabcab『)
為了方便理解,假設x+y=l,那麼我們恰好找到乙個(i−y,j+x−1)的』aa『串。
但是每次有乙個連續區間,我們不能乙個乙個加上,因為時效會出問題。所以用到差分的思想(當然有閒心寫線段樹也是可以的),在區間開始的地方加一,在區間結束的後乙個位置減一,那麼最後做一遍字首和即可。
【**】
//優秀的拆分
#include#include#include#include#define ll long long
#define m(a) memset(a,0,sizeof a)
#define fo(i,j,k) for(i=j;i<=k;i++)
using namespace std;
const
int mxn=30005;
int m,t,len;
char s[mxn];
int f[mxn],g[mxn]; //fi:以i結尾,gi:以i開頭
struct node
inline void work()
p=k=0;
fo(i,1,len) rank[sa[i]]=i;
for(i=1;i<=len;height[rank[i++]]=k)
for(k?k--:0,j=sa[rank[i]-1];a[i+k]==a[j+k];k++);
}inline void init()
inline int lcp(int x,int y)
}a,b;
int main()}}
fo(i,1,len) f[i]+=f[i-1];
fo(i,1,len) g[i]+=g[i-1];
fo(i,1,len
-1) ans+=(ll)f[i]*(ll)g[i+1];
printf("%lld\n",ans);
}return
0;}
bzoj4650 優秀的拆分
由於字串是aabb的形式,列舉aa和bb中間的位置,分別考慮aa和bb的數量,乘起來sigma一下即為答案 以下考慮aa的情況 bb同理 列舉a的長度,然後按照這個長度分為若干塊,那麼每乙個a一定可以表示成某一段的結尾 下一段的開頭,同時兩個a又要連續,也就是相鄰兩塊的lcp和lcs,用差分來維護即...
bzoj 4650 Noi2016 優秀的拆分
原來只會兩個log平衡樹合併。後來圍觀claris在uoj群上秒題後會了這道題。列舉a b 的長度l,然後列舉i kl,考慮字首i,i l和字尾i 1,i l 1,求出字首的lcp和字尾的lcp,然後合法的方案就在乙個方案內。差分一下即可。注意要避免重複。ac 如下 include include ...
BZOJ 4650 Noi2016 優秀的拆分
題解 求解每個位置向左向右aa串的個數f x g x 列舉a的長度,每a個位置設乙個關鍵點 每乙個a一定僅且跨越乙個關鍵點 然後求出相鄰關鍵點向前向後的最長公共字首的長度,這會對一段區間的f,g產生影響 用差分 字首和統計答案 include include include includeusing...