【BZOJ5314】[JSOI2018]潛入行動(動態規劃)
阿新 • • 發佈:2019-02-22
names pan getchar 集合 main def mat 全局 動態規劃
另外一種情況是一個子樹小於\(k\),經過合並之後變成大於\(k\)的子樹了,顯然對於一個點,如果它的子樹小於\(k\),在某次合並之後它的子樹就會大於\(k\),並且對於每個點而言,只會在他的某個祖先的地方經歷一次這樣子的合並,所以這樣子均攤每個點會產生\(O(k)\)的貢獻。
第三種情況是兩個點的子樹大小都小於\(k\),合並完之後兩者還是小於\(k\)。這個操作理解為每個兩個集合中的點一一對應的產生一次貢獻,那麽盯著某一個特定點考慮,它每次產生的貢獻是合並進來的子樹大小的,因為在這一部分的過程中子樹大小總是小於\(k\),因此每個點產生的貢獻也最多是\(O(k)\)的。
綜上,在三種合並情況中,每種情況產生的貢獻都最多是\(O(nk)\) 的,所以全局的復雜度就是\(O(nk)\)。
【BZOJ5314】[JSOI2018]潛入行動(動態規劃)
題面
BZOJ
洛谷
題解
不難想到一個沙雕\(dp\),設\(f[i][j][0/1][0/1]\)表示當前點\(i\),子樹中一共放了\(j\)個,這個點是否放了,這個是否被覆蓋了。
看起來直接合並是\(O(nk^2)\)的QwQ。。。。。
然後我以為是\(O(nk^2)\)的就不會做了嚶嚶嚶。
實際上是\(O(nk)\)的。。。
證明大概是這樣的:
考慮什麽時候會產生\(O(k^2)\)的貢獻,即一個點有兩棵子樹的大小大於\(k\),而這樣子合並次數不會超過\(O(\frac{n}{k})\),所以這部分的復雜度是\(O(nk)\)的。
第三種情況是兩個點的子樹大小都小於\(k\),合並完之後兩者還是小於\(k\)。這個操作理解為每個兩個集合中的點一一對應的產生一次貢獻,那麽盯著某一個特定點考慮,它每次產生的貢獻是合並進來的子樹大小的,因為在這一部分的過程中子樹大小總是小於\(k\),因此每個點產生的貢獻也最多是\(O(k)\)的。
綜上,在三種合並情況中,每種情況產生的貢獻都最多是\(O(nk)\)
#include<iostream> #include<cstdio> using namespace std; #define MAX 100100 #define MOD 1000000007 void add(int &x,int y){x+=y;if(x>=MOD)x-=MOD;} inline int read() { int x=0;bool t=false;char ch=getchar(); while((ch<'0'||ch>'9')&&ch!='-')ch=getchar(); if(ch=='-')t=true,ch=getchar(); while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar(); return t?-x:x; } struct Line{int v,next;}e[MAX<<1]; int h[MAX],cnt=1; inline void Add(int u,int v){e[cnt]=(Line){v,h[u]};h[u]=cnt++;} int n,K,f[MAX][101][2][2],size[MAX]; int tmp[101][2][2]; void dfs(int u,int ff) { size[u]=1;f[u][0][0][0]=1;f[u][1][1][0]=1; for(int i=h[u];i;i=e[i].next) { int v=e[i].v;if(v==ff)continue;dfs(v,u); for(int j=0;j<=size[u]&&j<=K;++j) for(int k=0;k<=size[v]&&j+k<=K;++k) { if(f[u][j][0][0]) { add(tmp[j+k][0][0],1ll*f[u][j][0][0]*f[v][k][0][1]%MOD); add(tmp[j+k][0][1],1ll*f[u][j][0][0]*f[v][k][1][1]%MOD); } if(f[u][j][0][1]) { add(tmp[j+k][0][1],1ll*f[u][j][0][1]*(f[v][k][0][1]+f[v][k][1][1])%MOD); } if(f[u][j][1][0]) { add(tmp[j+k][1][0],1ll*f[u][j][1][0]*(f[v][k][0][0]+f[v][k][0][1])%MOD); add(tmp[j+k][1][1],1ll*f[u][j][1][0]*(f[v][k][1][0]+f[v][k][1][1])%MOD); } if(f[u][j][1][1]) { int s=0; add(s,f[v][k][0][0]);add(s,f[v][k][0][1]); add(s,f[v][k][1][0]);add(s,f[v][k][1][1]); add(tmp[j+k][1][1],1ll*f[u][j][1][1]*s%MOD); } } size[u]+=size[v]; for(int j=0;j<=size[u]&&j<=K;++j) { f[u][j][0][0]=tmp[j][0][0];tmp[j][0][0]=0; f[u][j][0][1]=tmp[j][0][1];tmp[j][0][1]=0; f[u][j][1][0]=tmp[j][1][0];tmp[j][1][0]=0; f[u][j][1][1]=tmp[j][1][1];tmp[j][1][1]=0; } } } int main() { n=read();K=read(); for(int i=1,u,v;i<n;++i)u=read(),v=read(),Add(u,v),Add(v,u); dfs(1,0); int ans=(f[1][K][0][1]+f[1][K][1][1])%MOD; printf("%d\n",ans); return 0; }
【BZOJ5314】[JSOI2018]潛入行動(動態規劃)