2018 10 05 校內模擬 二分 狀壓 樹剖

2021-08-28 18:41:42 字數 4440 閱讀 3122

t1: 階乘

fact.cpp

【問題描述】

有 n個正整數 a[i],設它們乘積為 p,你可以給 p乘上乙個正整數 q,使 p*q剛好為正

整數m的階乘,求m的最小值。

【輸入】

共兩行。

第一行乙個正整數n。

第二行n個正整數a[i]。

【輸出】

共一行乙個正整數m。

【輸入樣例】16

【輸出樣例】

3樣例解釋:

當p=6,q=1時,p*q=3!

【資料範圍與約定】

對於10%的資料,n<=10

對於30%的資料,n<=1000

對於100%的資料,n<=100000,a[i]<=100000

分析:二分m

二分的上界要稍微大點,1e8,不然會漏掉答案。

驗證時對p分解質因子,然後求出m!裡面有多少個p的各個質因子,如果都比p多,那麼m就合法。

**:

#include

#include

#include

#define ll long long

#define n 600007

using

namespace std;

ll n, zs[n]

, t, a[n]

;

ll tot =

1, ans;

bool b[n]

;void

pre_work()

else

}}

ll max

(ll a, ll b)

void

cl(ll x)

a[zs[i]]++

, t =

max(t, zs[i]);

}}bool

check

(ll ain)

return1;

}void

find()

printf

("%lld"

, l);}

intmain()

cl(x);}

find()

;return0;

}

t2:上公升序列

(lis)

【問題描述】

給出乙個長度為 m 的上公升序列 a(1 ≤ a[i]≤ n), 請你求出有多少種 1…n 的排列, 滿足

a 是它的乙個 lis.

【輸入】

第一行兩個整數 n,m.

接下來一行 m 個整數, 表示 a.

【輸出】

一行乙個整數表示答案.

【輸入樣例1】

5 31 3 4

【輸出樣例1】

11【輸入樣例2】

4 23 4

【輸出樣例2】

5【資料範圍與約定】

對於前 30% 的資料, n ≤ 9;

對於前 60% 的資料, n ≤ 12;

對於 100% 的資料, 1 ≤ m ≤ n ≤ 15.

狀壓dp好題。

首先需要回憶o(nlogn)o(nlogn) 的方法,我們會維護乙個單調遞增的d陣列。

可以設計狀態f(s1,s2)表示選取的數的集合是s1,然後d陣列中元素的出現情況是s2。

這樣轉移是很簡單的。

但時空都無法承受。

於是我們考慮優化,不難發現s1是s2的子集。

因此我們三進製狀壓dp就行了。

**

#include

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

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

#define n 16

#define m 14348910

#define ll long long

using

namespace std;

int n,m,cf[n]

,a[n]

,wz[n]

,cf2[n]

;

ll f[m]

,ans;

void

dfs(

int k,

int lim,

int v)

v+=cf[k-1]

;dfs

(k+1

,lim,v)

;

v+=cf[k-1]

;dfs

(k+1

,lim-

1,v);}

intmain()

}if(c1)

if(f[vi])fo

(j,1

,n)

f[v]

+=f[vi];}

}if(i1==0)

break;}

}}dfs(

1,m,0)

;printf

("%lld\n"

,ans)

;return0;

}

t3 :相遇

(meet)

【問題描述】

豪哥生活在乙個 n 個點的樹形城市裡面,每一天都要走來走去。雖然走的是比較的

多,但是豪哥在這個城市裡面的朋友並不是很多。

當某一天,猴哥給他展現了一下大佬風範之後,豪哥決定要獲得一些交往機會來提公升交

往能力。豪哥現在已經物色上了一條友,打算和它(豪哥並不讓吃瓜群眾知道性別)交

往。豪哥現在 spy 了一下這個人的所有行程起點和終點,豪哥打算從終點開始走到起點與

其相遇。但是豪哥是想找話題的,他想知道以前有多少次行程和此次行程是有交集的,這

樣豪哥就可以搭上話了。這個路徑與之前路徑的有交集數量作為豪哥此次的交往機會。

但是豪哥急著要做交往準備,所以算什麼交往機會的小事情就交給你了。

【輸入】

第一行乙個正整數 n表示節點個數。接下來 n-1行,每行兩個正整數分別是 u,v表示節點

u和 v之間有連邊。接下來一行乙個 正整數 m表示路徑個數。然後有 m行,每行兩個正整

數分別是u,v分別表示 u到v之間有一條路徑。

【輸出】

輸出共m行,每行乙個整數,第 i行表示豪哥在這條路徑上獲得的交往機會。

【輸入樣例】

51 2

1 33 4

3 54

4 54 2

1 31 2

【輸出樣例】01

22【資料範圍與約定】

對於20%的資料n,m≤2000

對於另外20%的資料n,m≤50000

對於另外10%的資料n,m≤200000保證樹形結構是一條鏈

對於另外50%的資料n,m≤200000

分析:兩條路徑相交的情況就是:

1、這條路徑的lca在另一條路徑上。

2、某條路徑穿過這條路徑的lca。

我們用兩個樹狀陣列來維護,用dfs序。

對於第一種情況,我們維護這個點到根節點的路徑上面有多少個lca,然後相減就能得到答案。

對於第二種情況,我們在兩個節點上面打乙個+1的標記,在lca上面打乙個-2的標記,這樣就將整條鏈都+1了。

**:

#include

#define lowbit(x) ((x)&-(x))

#define treesum(t,x) (sum(t,r[x])-sum(t,l[x]-1))

using

namespace std;

const

int n=

2e5+10;

int n,m,l[n]

,r[n]

,stm;

int tot,to[n*2]

,next[n*2]

,final[n]

;int f[n][19

],dep[n]

;int t1[n]

,t2[n]

,ans;

void

change

(int

*tr,

int x,

int v)

intsum

(int

*tr,

int x)

void

link

(int x,

int y)

void

dfs(

int x,

int fa)

intlca

(int x,

int y)

void

calcans

(int x,

int y,

int lca)

intmain()

dfs(1,

0); cin>>m;

for(

int i=

1; i<=m; i++

)return0;

}

校內模擬 深邃(貪心)(二分答案)

簡要題意 一棵樹,有 k kk 個關鍵點,請你把樹劃分為若干聯通塊,使得每個聯通塊包含至少乙個關鍵點,最小化最大的聯通塊的大小。首先容易注意到可以二分答案。然後考慮怎麼判斷,進行dfs,每個點盡量貪心往下劃分。h vu hv u hvu 表示 u uu 為根的子樹,u uu 這個聯通塊還能多容吶的點...

校內模擬 記憶(狀壓DP)

考場想到了正解,然後被卡快取記憶體,gg 乙個顯然的轉化就是設e ie i ei 表示朋友選擇第i ii個串的時候的期望操作次數。則答案就是所有e ie i ei 的平均值。首先考慮乙個o n l2l o nl2 l o nl2l 的暴力,對於每個串,列舉所有其他串看有多少個位置相同,則我們能夠知道...

2018 10 17 校內模擬 管道(狀壓DP)

簡直有毒,出題人還一本正經的說 我覺得沒有去年noi pd2t 2noipd2t2 noipd2 t2難啊 我只想說,去年d2t 2d2t2 d2t2 的轉移方程那裡有這麼鬼畜。首先利用兩個陣列f,d pf textdp f,dp 來進行狀態轉移。定義如下fi,staf fi,sta 表示不向點i ...