NOIP模擬 項鍊

2021-07-15 03:30:17 字數 3140 閱讀 8093

經過一番周折,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...