题解:P12002 吃猫粮的玉桂狗
j23wuyifan · · 题解
一道很好的 dp 题,感觉之前有见过这种套路,一下还是不会做。
题目中的限制
其中
接下来考虑求有一种猫粮超出数量限制的方案。可以枚举超出限制的猫粮
总的不合法的方案就是:
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 55;
const int mod = 353442899;
int n,m,t,c[N];
vector<int> E[N];
bool vis[N][N];
int f[N][N][N],g[N][N],x,ans,sz[N];
//f[u][i][j] 表示在u点的猫粮种类是i一共选了j个种类x的猫粮
inline void dfs(int u,int fa){
sz[u] = 1;
for(int i = 1;i <= m;i ++)f[u][i][i == x] = 1;
for(int v : E[u]){
if(v == fa)continue;
dfs(v,u);
memset(g,0,sizeof(g));
for(int o = 1;o <= m;o ++){
for(int i = 1;i <= m;i ++){
if(vis[o][i])continue;
for(int j = 0;j <= sz[u];j ++){
for(int k = 0;k <= sz[v];k ++)
g[o][j + k] += f[u][o][j] * f[v][i][k] % mod;
}
}
}
sz[u] += sz[v];
for(int i = 1;i <= m;i ++)
for(int j = 0;j <= sz[u];j ++)f[u][i][j] = g[i][j] % mod;
}
}
//g[u][i]表示在u点猫粮种类是i的方案数
int f2[N][N];
inline void dfs2(int u,int fa){
for(int i = 1;i <= m;i ++)f2[u][i] = 1;
for(int v : E[u]){
if(v == fa)continue;
dfs2(v,u);
for(int i = 1;i <= m;i ++){
int cnt = 0;
for(int j = 1;j <= m;j ++)if(!vis[i][j])
cnt += f2[v][j];
f2[u][i] = f2[u][i] * cnt % mod;
}
}
}
signed main(){
cin >> n >> m >> t;
for(int i = 1;i <= m;i ++)cin >> c[i];
for(int i = 1;i < n;i ++){
int u,v;
cin >> u >> v;
E[u].push_back(v);
E[v].push_back(u);
}
for(int i = 1;i <= t;i ++){
int x,y;
cin >> x >> y;
vis[x][y] = 1;
}
//枚举超出数量限制的猫粮种类
for(x = 1;x <= m;x ++){
memset(f,0,sizeof(f));
dfs(1,0);
for(int k = 1;k <= m;k ++)
for(int j = c[x] + 1;j <= n;j ++)ans -= f[1][k][j];
ans %= mod;
}
dfs2(1,0);
for(int i = 1;i <= m;i ++)ans += f2[1][i];
ans %= mod;ans = (ans + mod) % mod;
cout << ans;
return 0;
}