HDU 5322 Hope 分治NTT優化DP

2022-03-25 20:56:47 字數 1814 閱讀 1998

題面傳送門

題目大意:

假設現在有乙個排列,每個數和在它右面第乙個比它大的數連一條無向邊,會形成很多聯通塊。

定義乙個聯通塊的權值為:聯通塊內元素數量的平方。

定義乙個排列的權值為:每個聯通塊的權值之積

求長度為$n$所有排列的權值之和,$n\leq 1e5$,$1e4$組詢問

原題面描述不清楚啊..害得我白想了30min

和zoj3874一樣都是排列$dp$問題 

$dp$方程還是不難想的

假設現在有乙個$i-1$的排列,當我們把$i$某個位置上時

$i$前面的數都會和$i$連通,$i$後面的數一定不和$i$前面的數連通

利用這個性質就可以$dp$了,定義$f[i]$表示長度為$i$的所有排列的權值之和

$f[i]$

$i$後面一共j個數可以在$i-1$個數中任選,$i$前面一共$i-j-1$個數可以任意排列,可得

$=\sum c_^f[j](i-j-1)!(i-j)^$

化簡$=(i-1)!\sum \frac(i-j)^$

發現這是乙個卷積的形式,用分治$ntt$解決即可

1 #include 2 #include 3 #include 4 #include 5

#define n1 (1<<18)+10

6#define il inline

7#define dd double

8#define ld long double

9#define ll long long

10using

namespace

std;

1112

const

int inf=0x3f3f3f3f;13

const ll p=998244353;14

intgint()

1518

while(c>='

0'&&c<='9')

19return ret*fh;20}

21ll qpow(ll x,ll y)

2227

28namespace

ntt39

void ntt(ll *s,int len,int type,int

l)4054}

55}56}

57void main(int len,int

l)58

65void clr(int

sz)66

7071

};72

73using ntt::a; using ntt::b; using

ntt::c;

74 ll f[n1],g[n1],ans[n1],mul[n1],_mul[n1]; int

de;75

void cdq(int l,int

r)76

82if(r-l<=1) return;83

int mid=(l+r)>>1

,i,len,l;

84cdq(l,mid);

85for(len=1,l=0;len<(mid-l)+(r-l)-1;len<<=1,l++);

86for(i=l;if[i];

87for(i=0;i<(r-l);i++) ntt::b[i]=g[i];

88ntt::main(len,l);

89for(i=mid;ip;

90ntt::clr(len);

91cdq(mid,r);92}

93int

t,n,m;

94int

que[n1];

9596

intmain()

97

HDU 4812 D Tree 點分治 逆元

題目要求在樹上找到一條鏈使得這條鏈上的點的乘積模mod等於k,求鏈首尾字典序最小的一條 看到題目就能知道是乙個點分治的題目,將樹按照重心分治之後,就是要統計以重心為根的子樹中,過樹根的mod為k的鏈字典序最小的一條,這裡的統計必需是在時間複雜度o n 以下才能過 pragma comment lin...

HDU 5324(分治 樹狀陣列)

本題目的原來意思是,給定兩個長度為n的陣列,l,r,要求乙個子串行 可以不連續 使的l遞減,r遞增。分析 加上下標遞增,兩個維度增,乙個減,那麼考慮 d i 代表以i為起點的串往後找能得到的最大長度,用分治方法更新最有值。那麼下面說一下,怎麼分治維護最優。首先,陣列原順序保持不變,就是下標遞增,對於...

hdu(1007) 最近點對 分治法

最近點對一般想到列舉 一一枚舉時間複雜度為n 2 列舉時候一些操作是多餘的,有了分治演算法的思想 把一些問題分個擊破,再回到整體。題目鏈結 以這道題為例,我們可以把他按照x軸的公升序分成多個子區域先在子區域中求最近點距離,然後將相鄰兩個子區域合併,看看兩個子區域中有沒有更小的。大致思想就是這樣的。設...