經過一番周折,bob找到了alice,為了安慰alice驚魂未定的心,bob決定給alice買一條手鍊,這條手鍊由m個珍珠組成,每個珍珠上刻著不同的小寫字母。當alice看到一些字母按照一定的順序排列成的字串時,就會產生一定的愉悅值。bob現在可以在這m個珍珠上刻上字母,現在他想知道,如何刻字母可以使得alice的愉悅值最大。
ac自動機
這是道很神奇的題目,我和一位同伴研究了乙個晚上才搞出來,心情自然愉悅。
有很多個字串,每次只用字首字尾匹配,自然可以想到ac自動機,這題和一道叫貼瓷磚的題很像。
ac自動機上dp
那麼我們在ac自動機上只有末尾節點才會有權值(注意,當前這個點的權值要加上fail邊連向的點的權值,而且判斷一下不能連向自己),但是無法確定當前狀態下的貢獻,我們考慮一下dp。
設f[i][j]表示在項鍊做到了第i個節點,走到ac自動機上的第j個節點所做的最大貢獻。
注意f的初始狀態,全部複製為乙個很小的負數,然後f[0][0]=0。否則ac自動機在項鍊的每個節點上沒有傳遞性就會亂跳。
轉移很顯然,列舉當前項鍊的第i個點弄成字母k(找不到乙個好的動詞) f[
i][j
]=ma
x(f[
i][j
],f[
i−1]
[x]+
trie
[x].
zhi)
(x是a
c自動機
上j節點
走到乙個
字母k轉
移到的節
點,tr
ie[x
].zh
i表示x
節點的貢
獻)然後這樣做的複雜度十分的大。
找乙個b陣列
我們可以發現所有的trie[x].zhi是不變的,那麼我們可以找到乙個b陣列,b[i][j]表示ac自動機上i節點跳到j節點的貢獻。
那麼b陣列怎麼去找呢?
我們對dp轉移時進行觀察,j會轉移到很多的x,那麼這個時候才會對答案有貢獻,所以所有在ac自動機上的j能轉移到x的節點b[
j][x
]=ma
x(b[
j][x
],tr
ie[x
].zh
i),很顯然是取最大值。
找到b陣列之後dp轉移式就可以變為 f[
i][j
]=ma
x(f[
i][j
],f[
i−1]
[x]+
b[j]
[x])
雖然複雜度還是不變的,但是這樣的dp更加具有傳遞性,這樣有什麼用呢?
矩陣乘法
觀察f陣列的轉移,後面的地方十分的像矩陣乘法,但是是取最大值,中間還是加號?????這樣有什麼關係呢,矩陣乘法的時候
c.ju[i][j]=max(c.ju[i][j],a.ju[i][k]+b.ju[k][j]);
這樣打就可以了,這樣矩陣還是滿足結合律,只要矩陣滿足結合律,就可以矩陣乘法(不一定用乘法運算,但不加矩陣加法,只是這樣轉移而已)。
那麼把b陣列放進乙個矩陣裡面,然後打乙個矩陣快速冪,然後再把f陣列放進乙個矩陣裡面,兩個矩陣相乘就可以了。
所有的矩陣初始值都是乙個很小的負數,因為要取最大值嘛。
max的矩陣乘法要注意
ma qsm(ma
x,int
y) return z;
}
以前矩陣乘法的快速冪我是這樣打的,但是這題的運算操作不是乘法啊,還要去最大值啊,怎麼辦怎麼辦???
ll y=m-1;
fo(i,0,num)fo(j,0,num)z.ju[i][j]=c.ju[i][j];
while(y!=0)
g=g*z;
打成這個樣子就可以避免問題了。
這題會爆棧
所以上面的那麼矩陣乘法我是打在主程式裡面的,然後就可以ac了。
自動ac機。。。。。。
#include
#include
#include
#include
#include
#define fo(i,a,b) for(i=a;i<=b;i++)
using
namespace
std;
typedef
long
long ll;
const
int maxn=100007;
ll i,j,k,l,t,n,m;
ll a[maxn],fail[maxn],x,len,num,data[maxn];
ll b[1000][1000],d[1000];
char s[207][207];
ll ans;
struct nodetrie[maxn];
struct ma}}
return c;
}}c,ber,g;
void ac_automation()}}
}int main()
memset(b,200,sizeof(b));
memset(c.ju,200,sizeof(c.ju));
memset(g.ju,200,sizeof(g.ju));
fo(i,1,n)
else x=trie[x].son[s[i][j]-'a'];
}trie[x].zhi+=a[i];
}ac_automation();
x=0;
g.ju[0][0]=0;
fo(j,0,num)
}ma z;int i,j;
ll y=m-1;
fo(i,0,num)fo(j,0,num)z.ju[i][j]=c.ju[i][j];
while(y!=0)
g=g*z;
fo(j,0,num)ans=max(g.ju[0][j],ans);
printf("%lld\n",ans);
}
NOIP2006(能量項鍊)
program energy var n,m longint head,tail array 1.200 of longint head i 與tail i 分別表示第i個珠子的頭標記與第i個珠子的尾標記。f array 1.200,1.200 of longint f i,j 表示從第i個珠子到第...
NOIP200605能量項鍊
試題描述 在mars星球上,每個mars人都隨身佩帶著一串能量項鍊。在項鍊上有n顆能量珠。能量珠是一顆有頭標記與尾標記的珠子,這些標記對應著某個正整數。並且,對於相鄰的兩顆珠子,前一顆珠子的尾標記一定等於後一顆珠子的頭標記。因為只有這樣,通過吸盤 吸盤是mars人吸收能量的一種器官 的作用,這兩顆珠...
NOIP 2006 能量項鍊
洛谷傳送門 jdoj傳送門1 jdoj傳送門2 在mars星球上,每個mars人都隨身佩帶著一串能量項鍊。在項鍊上有n顆能量珠。能量珠是一顆有頭標記與尾標記的珠子,這些標記對應著某個正整數。並且,對於相鄰的兩顆珠子,前一顆珠子的尾標記一定等於後一顆珠子的頭標記。因為只有這樣,通過吸盤 吸盤是mars...