考場上想到的o(n
2)o(n^2)
o(n2
)暴力:
記f [i
][j]
f[i][j]
f[i][j
]表示前i個位置,長度為j的連擊出現的期望次數
記g [i
][j]
g[i][j]
g[i][j
]表示第到i個位置為止,目前連擊次數為j的概率
轉移時有一些細節
#include
using
namespace std;
const
int maxn=
5e4+5;
inline
intread()
while
(isdigit
(c))
return t*f;
}int n;
double a[maxn]
,f[2
][maxn]
,g[2
][maxn]
;int
main()
g[i&1]
[0]=
0;f[i&1]
[0]=
0;for(
int j=
1;j<=i;j++
)for
(int j=
0;jfor(
int i=
1;i<=n;i++
) f[n&1]
[0]=
0;for(
int i=
0;i<=n;i++
)return0;
}
然後是正解:
記p[i]表示前i個位置都連擊,在第i+1個位置斷連的概率
記q[i]表示恰好從第i個位置開始連擊的概率.
記ans[i]表示最終連擊長度恰好為i的期望次數
然後發現如果將p或q翻轉,ans可以直接由p和q多項式乘法得到
這裡首先給出暴力,更便於理解
#include
const
int maxn=
50005
;double a[maxn]
,s[maxn]
,p[maxn]
,q[maxn]
,ans[maxn]
;int n,i,j;
intmain()
for(i=
0;i<=n;i++
)for
(i=1
;i<=n;i++
)for
(j=0
;j) ans[i-j]
+=p[i]
*q[j]
;//這裡就表示[j+1,i]這個區間全連,而j和i+1都斷開的概率
for(i=
0;i<=n;i++
)printf
("%.12lf\n"
,ans[i]);
}
正解
#include
using
namespace std;
const
double pi=
acos(-
1);const
int maxn=
200005
;double a[maxn]
,s[maxn]
,p[maxn]
,q[maxn]
,ans[maxn]
;int n,i,j,lim=
1,l,r[maxn]
;struct node
}ans1[maxn]
,p1[maxn]
,q1[maxn]
;node operator
+(node a,node b)
node operator
*(node a,node b)
node operator
-(node a,node b)
void
fft(node a,
int lim,
int f)}}
}int
main()
for(i=
0;i<=n;i++
)reverse
(p+1
,p+1
+n);
while
(lim<=
(n+n)
)lim<<=
1,l++
;for
(int i=
1;i)r[i]
=(r[i>>1]
>>1)
|(i&1)
<<
(l-1);
for(
int i=
0;i)fft
(p1,lim,1)
;fft
(q1,lim,1)
;for
(int i=
0;i)ans1[i]
=p1[i]
*q1[i]
;fft
(ans1,lim,-1
);reverse
(ans1+
1,ans1+
1+n)
; ans1[0]
.x=0
;for
(i=0
;i<=n;i++
)printf
("%.12lf\n"
,ans1[i]
.x/lim)
;}
一道互動練習題
的做法 考慮逐位確定 對於每個位置,往後列舉有沒有位置可以使得正確位置更多,如果有,那麼有兩種情況,1是這個位置被放到了正確的位置,2是這個位置本來應該放的數被放來了 這裡的重點是我們需要區分1和2 具體的做法是記下讓這個位置答案正確位置數變大的2個位置,將其和i一起移位 這裡是手繪示意圖.即把p1...
一道sam練習題
考慮答案實際上是每個子串的出現次數的平方和.這個可以通過手玩樣例驗證.考慮廣義sam 先將所有字串建成trie,然後再在trie上bfs,建出sam.考慮fail樹 每次插入乙個新節點,會改變從這個節點開始到根的路徑上的每個節點的right集合大小.所以考慮樹剖維護這種操作,然後每乙個單詞的答案就是...
一道線段樹練習題
e9首先我們有乙個考慮列舉每個mex,計算其貢獻的想法.即有多少個區間的mex mexme x是我們當前列舉的這個值.然後我們手畫一下圖,可以發現,乙個數如果想要成為乙個區間的mex mexme x,必須要這個區間已經出現了所有比它小的數.所以可以從小到大列舉mex mexme x,然後用r rr陣...