題解 P7846 「dWoi R2」Arcade hall / 街機廳
阿新 • • 發佈:2021-10-25
\(\quad\)可以發現第一問和第二問並無關聯,所以可以分開討論。
第一問
\(\quad\)顯然是樹形DP,可以從上向下DP,\(f_i\) 表示 \(i\) 號結點可能的方案數,\(son_i\) 為 \(i\) 號結點的兒子數,設 \(j\) 為i的一個兒子,\(val_{i,j}\) 為 \(i,j\) 連邊的關係(\(t\))。
\(\quad\)可得:
\[ \left\{ \begin{aligned} & f_{root}= R\\ & f_j= & R-1(val_{i,j}=0)\\ & f_j= & R(val_{i,j}=1)\\ & f_j= & 1(val_{i,j}=2) \end{aligned} \right. \]\(\quad\)
第二問
\(\quad\)同樣是樹形DP,但是是從下向上傳遞答案,設 \(g_{i,j}\) 為 \(i\) 號結點取 \(j\) 時子樹的最小值,R並不大,所以可以逐一列舉。(經測試,列舉到13即可)
\(\quad\)可得:(設 \(p_{i,0}\) 為 \(g_{i,j}\)中的最小值, \(p_{i,1}\) 為次小值, \(v\) 為 \(i\) 的一個兒子)
\[g_{i,j}=j \]\[ \left\{ \begin{aligned} & g_{i,j}+= p_{v,0} (val_{i,v}=0,p_{v,1}>=g_{v,j})\\ & g_{i,j}+= p_{v,1} (val_{i,v}=0,p_{v,1}<g_{v,j})\\ & g_{i,j}+= p_{v,0} (val_{i,v}=1)\\ & g_{i,j}+= g_{v,j}(val_{i,v}=2) \end{aligned} \right. \]\(\quad\)
\[\texttt{後記} \]#include<iostream> #include<cstdio> #include<cmath> #include<cstring> #include<cstdlib> #include<time.h> #define int long long #define re register int #define il inline using namespace std; il int read() { int x=0,f=1;char ch=getchar(); while(!isdigit(ch)&&ch!='-')ch=getchar(); if(ch=='-')f=-1,ch=getchar(); while(isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar(); return x*f; } il void print(int x) { if(x<0)putchar('-'),x=-x; if(x/10)print(x/10); putchar(x%10+'0'); } il int min(int x,int y){return x<y?x:y;} const int N=1e5+5,MOD=1e9+7,inf=0x3f3f3f3f; int n,R,p,rt,tot,ans=1,head[N],nxt[N<<1],val[N<<1],go[N<<1],f[N],g[N][15]; il void Add(int x,int y,int z) { nxt[++tot]=head[x]; head[x]=tot;go[tot]=y;val[tot]=z; } il void dfs(int x,int fa,int h)//g[i][0]表示最小值,g[i][14]表示次小值 { for(re i=1;i<=p;i++)g[x][i]=i;//初始的代價 if(h==1)f[x]=R;else if(h==2)f[x]=1;else f[x]=R-1;//第一問 for(re i=head[x],y;i,y=go[i];i=nxt[i]) if(y!=fa){ dfs(y,x,val[i]); for(re j=1;j<=p;j++) if(val[i]==1)g[x][j]+=g[y][0]; else if(val[i]==2)g[x][j]+=g[y][j]; else { if(g[y][j]>=g[y][14])g[x][j]+=g[y][0]; else g[x][j]+=g[y][14]; } } g[x][0]=g[x][14]=inf; for(re i=1;i<=p;i++)//更新最小值和次小值 { if(g[x][i]<g[x][0])g[x][14]=g[x][0],g[x][0]=g[x][i]; else if(g[x][i]==g[x][0])g[x][14]=g[x][i]; else if(g[x][i]<g[x][14])g[x][14]=g[x][i]; } } signed main() { n=read();R=read();srand(time(0));rt=rand()%n+1;p=min(R,13);//隨機的根不容易被卡 for(re i=1,x,y,z;i<n;i++)x=read(),y=read(),z=read(),Add(x,y,z),Add(y,x,z); dfs(rt,0,1); for(re i=1;i<=n;i++)ans=(ans*f[i])%MOD;//記得要取模 print(ans);putchar(' ');if(ans==0){putchar('0');return 0;} print(g[rt][0]); return 0; }
\(\quad\)一開始以為只填1或2就是最小值,然而只有30分,至今不知道為什麼?
\(\quad\)這裡有一組資料,有大佬可以解釋嗎?