考場想到了正解,然後被卡快取記憶體,gg
乙個顯然的轉化就是設e
ie_i
ei表示朋友選擇第i
ii個串的時候的期望操作次數。則答案就是所有e
ie_i
ei的平均值。
首先考慮乙個o(n
l2l)
o(nl2^l)
o(nl2l
)的暴力,對於每個串,列舉所有其他串看有多少個位置相同,則我們能夠知道選取哪些位置集合不能辨別這個串,則這些集合的任意乙個子集都不能辨別這個串,則我們直接考慮選擇某乙個位置之後選取狀態s→t
s\rightarrow t
s→t,其中s
ss是非法狀態,t
tt是合法狀態。
我們突然發現如果乙個集合無法辨別某個子串,則任意子集都無法辨別。
設c nt
[s
]cnt[s]
cnt[s]
表示s
ss狀態無法分辨的子串個數,則cnt
[s]−
cnt[
t]
cnt[s]-cnt[t]
cnt[s]
−cnt
[t]就能夠表示在s→t
s\rightarrow t
s→t這一步中被辨別的子串個數,也就可以算貢獻了。
處理請參考**裡面的注釋,對,就是考場上寫的注釋
**:
#include
#define ll long long
#define re register
#define cs const
int n,l,s;
ll match[22]
[513];
// match[i][c] 第 i 位為 c 的字串集合
ll same[
1<<20|
1][52
];// same[s][i] 詢問狀態為 s 的時候無法與 i 區分的串的集合
short cnt[
1<<20|
1];// cnt[s] 詢問狀態為 s 的情況下無法區分的串的數量
//long double dp[1<<20|1]// 詢問到 s 狀態的概率。這個好像是組合數,1/
long
double c[22]
;short ctz[
1<<20|
1],pc[
1<<20|
1];// ctz popcount
inline
void
init()
for(
int re i=
0;i<=l;
++i)c[i]
=c[l]
[i];
for(
int re i=
1;i++i)ctz[i]
=(i&1)
?0:(ctz[i>>1]
+1),pc[i]
=pc[i>>1]
+(i&1)
;}#ifdef zxyoi
#undef zxyoi
#endif
char s[52]
[22];
#define lb(x) ((x)&-(x))
signed
main()
cnt[0]
=n;for
(int re s=
1;s++s)
}long
double ans=0;
for(
int re s=
1;s++s)
printf
("%.10f",(
double
)(ans/n));
return0;
}
2018 10 17 校內模擬 管道(狀壓DP)
簡直有毒,出題人還一本正經的說 我覺得沒有去年noi pd2t 2noipd2t2 noipd2 t2難啊 我只想說,去年d2t 2d2t2 d2t2 的轉移方程那裡有這麼鬼畜。首先利用兩個陣列f,d pf textdp f,dp 來進行狀態轉移。定義如下fi,staf fi,sta 表示不向點i ...
校內模擬 排列(狀壓DP)(矩陣快速冪)
簡要題意 統計有多少個不同的 n nn 排列滿足 pi i k p i i leq k pi i k k 4 k leq 4 k 4 容易發現當前位置選擇哪乙個只會影響到後面 k kk 個位置。k kk 本身非常小,狀壓即可。容易發現轉移和當前是第幾位無關,只和狀態有關,而且是線性,寫成矩陣然後快速...
NOIP模擬 乘積(狀壓DP)
題意 選擇不超過 k 個 n以內的正整數撐起來,使得乘積是乙個無平方因子數 不能夠被任意乙個質數的平方整除 一共有多少種取法?n 500,k 500 題解 首先,很容易想到狀壓,壓縮當前已經選過某質數的狀態。對於質數個數小於 20 可以直接過,但是問題是現在 n 以內的質數個數很多,無法壓縮。考慮狀...