字串程式碼-先自學-學會查api和百度
阿新 • • 發佈:2022-05-25
http://www.nfls.com.cn:10688/contest/536/problem/2
機器人 題解
令結點 x 上有\(a_x\)個不同的物品,題目要求每個連通塊的物品數之和的成績,就可以轉化成在每個連通塊內只選一個物品的方案數,因此,我們設計出dp。設\(f[u][i][j]\)表示以 u 為根的子樹,連通塊個數為 i,以及 u 縮在的連通塊內是否選過物品(\(j=0/1\))。
轉移時列舉\((u,v)\)並分成兩種情況,斷邊和不斷邊的情況,樹上揹包合併。注意,每一次合併的時候,等價於在包含 u 的子樹裡選不超過 k 個點,在包含 v 的子樹裡選擇不超過 k 兩個點,因為兩者的 dfs序 連續,所以每個節點最多與 4k 個結點合併,即 dfs序 上排在 u 之前的 2k 個和排在 u 之後的 2k 。然後轉移結束後,對於每個\(f[u][i][0]\)
點選檢視程式碼
//CAN'T FORGET //CAN'T FORGET //CAN'T FORGET //#pragma GCC optimize("Ofast") #include<bits/stdc++.h> using namespace std; #define _ 0 const long long maxn=4e4+5; const long long maxm=1e6+5; const long long mod=998244353; const long long inf=0x3f3f3f3f; inline long long read() { long long x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } return x*f; } struct node{ long long to,nxt; }edge[maxm]; long long head[maxm],tot; void addedge(long long u,long long v) { edge[++tot].to=v; edge[tot].nxt=head[u]; head[u]=tot; } long long n,k; long long a[maxn],sz[maxn],f[maxn][1005][2],dp[maxn][2]; void DP(long long x,long long y) { for(long long a=1;a<=sz[x]&&a<=k;a++) { for(long long b=1;b<=sz[y]&&a+b-1<=k;b++) { dp[a+b-1][0]+=f[x][a][0]*f[y][b][0]%mod; dp[a+b-1][1]+=f[x][a][0]*f[y][b][1]%mod; dp[a+b-1][1]+=f[x][a][1]*f[y][b][0]%mod; dp[a+b-1][0]%=mod; dp[a+b-1][1]%=mod; dp[a+b-1][1]%=mod; if(a+b-1==k) break; dp[a+b][0]+=f[x][a][0]*f[y][b][1]%mod; dp[a+b][1]+=f[x][a][1]*f[y][b][1]%mod; dp[a+b][0]%=mod; dp[a+b][1]%=mod; } } sz[x]+=sz[y]; for(long long i=1;i<=sz[x]&&i<=k;i++) { f[x][i][0]=dp[i][0]; f[x][i][1]=dp[i][1]; dp[i][0]=0; dp[i][1]=0; } } void dfs(long long x,long long fa) { sz[x]=1; f[x][1][0]=1; for(long long i=head[x];i;i=edge[i].nxt) { long long y=edge[i].to; if(y==fa) continue; dfs(y,x); DP(x,y); } for(long long i=1;i<=sz[x]&&i<=k;i++) { f[x][i][1]+=f[x][i][0]*a[x]%mod; f[x][i][1]%=mod; } } int main(){ ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); // freopen("robot.in","r",stdin); // freopen("robot.out","w",stdout); cin>>n>>k; for(long long i=1;i<=n;i++) cin>>a[i]; for(long long i=1;i<=n-1;i++) { long long u,v; cin>>u>>v; addedge(u,v); addedge(v,u); } dfs(1,0); cout<<f[1][k][1]<<endl; return ~~(0^_^0); } /* Notes: 1.看所有題目 2.注意資料範圍 3.想想自己還能做什麼而不是做了什麼 4.看清題目!!! 5.記得把除錯程式碼刪掉!!!! 6.longlong時 1要寫成1ll 7.Think twice code once, think once code forever! */