loj6402 校門外的樹 dp,多項式求逆

2022-06-03 20:54:09 字數 3093 閱讀 8753

慶祝一下,,,第乙個我自己做出來的,,,多項式的題(沒辦法,我太弱

雖然用了2個小時才想出來,但這畢竟是0的突破……

首先宣告,雖然我寫的題解很長,但是大部分都是證明和廢話

第一步,轉化題意(用時30min):

乙個1~n的全排列$p$,如果存在$i

問所有p的所有排列方案,最後聯通塊的大小的乘積,的和。

因為原題中$a$是隨機的實數,所以說我們可以不用考慮有$a_i=a_j$的情況。

因為最後用到的只有相對的大小關係,所以可以直接轉化成乙個1~n的排列$p$。

其實很多時間都花在"誒,是這個意思嗎,不會啊","哦,不對,看錯題了"。

第二步,找規律推性質(用時50min):

我們發現,乙個聯通塊,一定是$l$到$r$連續的一段。

假如說,$a$和$b$在同乙個聯通塊內(令$a

我們來證明這種情況是不存在的。

首先,$p[b]

那麼$p[a]>p[b]$,但是他們在同乙個聯通塊內,

所以一定存在乙個位置$x$滿足$xb,p[x]>p[a]$

那麼$x$一定與$c$直接相連,所以證出矛盾。

同理,我們可以證到乙個聯通塊的$p$也是連續的一段。

但是我不是這麼找到這個性質的,因為我上面的方法只是證明了這個性質,但是如果我猜不到這個性質……

我按照套路思考,每個聯通塊找乙個代表員好了,找誰呢,那就$p$最小的那個吧。

我們把點放在乙個平面上,第$i$個點的座標是$(i,p[i])$。

我們按照$p$從小到大,加入每個點。

首先,$p$最小的那個點加入的時候,我們考慮找它所在的聯通塊的點。

找到乙個滿足$p[j]>p[i]$的最大的$j$,那麼$i$到$j$這個連續區間的所有點都在同乙個聯通塊內。

(把這些點分成$p[x]p[j]>p[i]$兩種情況討論就可以了)

然後$然後我們把這些點刪掉,再找到$p$最小的那個點,遞迴下去。

我們發現,我們把乙個n*n的矩形,一次一次的減去乙個聯通塊所在的"勢力範圍",其實是一次一次砍掉了右邊的一條和下面的一條,剩下的還是乙個矩形。

如圖:

其中淡粉色是乙個聯通塊的勢力範圍,$t$是這個聯通塊$p$最大的點,$k$是這個聯通塊最靠左(就是編號最小)的點。

我們再找下乙個聯通塊的時候,下乙個聯通塊勢力範圍一定是在白色部分。

所以下乙個聯通塊的$p$最小的點的一定有$p[x]>p[t]$,編號最大的點$x

於是我們兩個性質都找到啦。

有了這兩個性質之後,我們可以發現,乙個聯通塊$[l,r]$,一定滿足:$p[l],p[l+1],....,p[r-1],p[r]$一定是$n-l+1,n-(l+1)+1,....,n-r+1$的乙個排列。

同時$p[1],p[2],....,p[r]$一定是$n,n-1,...,n-r+1$的乙個排列。

同時$[l,r-1]$中不存在$x$滿足$p[1],p[2],....,p[x]$是$n,n-1,....,n-x+1$的乙個排列,否則就可以分出$[l,x],[x+1,r]$兩個聯通塊了。

也就是說,如果我們稱滿足$p[1],p[2],....,p[x]$是$n,n-1,....,n-x+1$的乙個排列的$x$是好的,那麼每個$x$都一定是乙個聯通塊的右端點。

第三步,推式子(用時40min):

有了上面的幾個性質,我們可以開始列$dp$方程了。

我們令$f(n)$表示1~n的乙個排列,除$n$位置外,不存在其他位置是好的,的方案數。

那麼$f(0)=0,f(1)=1$

$f(n)=n!-\sum\limits_^ i! f(n-i)$

令$g(n)=n!$,特別地,我們規定$g(0)=1$

那麼$f(n)=g(n)-\sum\limits_^ g(i) f(n-i)$

把$\sum$移到左邊,可以得到$\sum\limits_^ g(i) f(n-i) = g(n)$

我們發現這是乙個卷積形式$f*g+1=g$。(因為$f(0)=0,g(0)=1$)

令$dp(i)$表示前$i$個數,並且$i$是乙個聯通塊右端點,的貢獻。規定$dp(0)=1$

列舉上乙個聯通塊的右端點,那麼有:

$dp(n)=\sum\limits_^ (n-i) f(n-i) dp(i)$

令$h(n)=nf(n)$。$h(0)=0$

$dp(n)=\sum\limits_^ h(n-i) dp(i)$

又是乙個卷積形式$dp=dp*h+1$。(因為$h(0)=0,dp(0)=1$)

於是兩次多項式求逆就可以解決問題啦。

//serene

#include#include#include#include#include#includeusing namespace std;

#define ll long long

#define db double

#define for(i,a,b) for(int i=(a);i<=(b);++i)

#define rep(i,a,b) for(int i=(a);i>=(b);--i)

const ll mod=998244353,b=3;

const int maxn=1e7+7;

ll n,g[maxn],h[maxn],ginv[maxn],hinv[maxn],x[maxn];

templatevoid read(t& aa)

ll qp(ll x,ll k)

return rs;

}ll finv(ll x)

ll qp1(ll x,ll k)

void rader(ll f,ll len)

if(j>1,a,b);

ll n=1;for(;n<=(n<<1);n<<=1);

for(i,0,n-1) x[i]=a[i]; for(i,n,n) x[i]=b[i]=0;

fft(x,n,1); fft(b,n,1);

for(i,0,n) b[i]=b[i]*(2-b[i]*x[i]%mod+mod)%mod;

fft(b,n,-1); for(i,n,n) b[i]=0;

}int main()

校門外的樹

描述 某校大門外長度為 l的馬路上有一排樹,每兩棵相鄰的樹之間的間隔都是 1公尺。我們可以把馬路看成乙個數軸,馬路的一端在數軸 0的位置,另一端在 l的位置 數軸上的每個整數點,即0,1,2 l,都種有一棵樹。馬路上有一些區域要用來建地鐵,這些區域用它們在數軸上的起始點和終止點表示。已知任一區域的起...

校門外的樹

某校大門外長度為l的馬路上有一排樹,每兩棵相鄰的樹之間的間隔都是1公尺。我們可以把馬路看成乙個數軸,馬路的一端在數軸0的位置,另一端在l的位置 數軸上的每個整數點,即0,1,2,l,都種有一棵樹。由於馬路上有一些區域要用來建地鐵。這些區域用它們在數軸上的起始點和終止點表示。已知任一區域的起始點和終止...

校門外的樹

校門外的樹 題目描述 某校大門外長度為l的馬路上有一排樹,每兩棵相鄰的樹之間的間隔都是1公尺。我們可以把馬路看成乙個數軸,馬路的一端在數軸0的位置,另一端在l的位置 數軸上的每個整數點,即0,1,2,l,都種有一棵樹。由於馬路上有一些區域要用來建地鐵。這些區域用它們在數軸上的起始點和終止點表示。已知...