[JSOI2018] 潜入行动
P4516 [JSOI2018] 潜入行动
考虑DP
dp[u][i][0/1][0/1]表示 以u为根的子树中共放了i个 ,是否放了监听装置,是否被监听到
1.dp[u][i][0][0]表示 以u为根的子树中共放了i个 没放监听装置 没被监听到
2.dp[u][i][0][1]表示 以u为根的子树中共放了i个 没放监听装置 被监听到
4.dp[u][i][1][0]表示 以u为根的子树中共放了i个 放了监听装置 没被监听到
4.dp[u][i][1][1]表示 以u为根的子树中共放了i个 放了监听装置 被监听到
用01代替 是否放了监听装置,是否被监听到
然后由于是求方案数,子树方案相乘,分类讨论之后相加
结果为 dp[1][k][0][1]和dp[1][k][1][1] 两种被监听到的方案之和
对于多棵子树的结果我们合并到根节点
1.如果u没被监听,没放装置,v有 0,0 和 0,1两种状态
dp[u][i+j][0][0] = ∑dp[x][i][0][0]*dp[v][j][0][1]
2.如果u没被监听,放了装置,v有 0,0 和 0,1两种状态
dp[u][i+j][1][0] = ∑dp[x][i][1][0]*(dp[v][j][0][0]+dp[v][j][0][1])
3.如果u被监听了,没放装置,v有 0,0 、 0,1 、 1,1 、1,0 四种状态
dp[u][i+j][0][1] = ∑(dp[u][i][0][1]*(dp[v][j][0][1]+dp[v][j][1][1])+dp[u][i][0] [0]*dp[v][j][1][1])
4.如果u被监听了,放了装置,v有 0,0 、 0,1 、 1,1 、1,0 四种状态
dp[u][i+j][1][1] = ∑(dp[u][i][1][0]*(dp[v][j][1][0]+dp[v][j][1][1])+dp[u][i][1][1]*(dp[v][j][0][0]+dp[v][j][0][1]+dp[v][j][1][0]+dp[v][j][1][1]))
时间复杂度O(nk)
// P4516 [JSOI2018] 潜入行动
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+10;
const int mod=1e9+7;
int read() {
int x=0,f=1;
char ch=getchar();
while(ch<48||ch>57) {
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>=48&&ch<=57) {
x=(x<<3)+(x<<1)+(ch^48);
ch=getchar();
}
return x*f;
}
int head[N],to[N*2],nxt[N*2],tot=0;
void add(int u,int v) {
nxt[++tot]=head[u];
to[tot]=v;
head[u]=tot;
}
int n,k,dp[N][101][2][2];
int g[N][101][2],siz[N];
int get_mod(ll x,ll y) {
x%=mod;
y%=mod;
return (int)(x+y)%mod;
}
void dfs(int u,int fa) {
siz[u]=dp[u][0][0][0]=dp[u][1][1][0]=1;
for(int o=head[u]; o; o=nxt[o]) {
int v=to[o];
if(v==fa) continue;
dfs(v,u);
for(int i=0; i<=min(siz[u],k); i++) {
g[i][0][0]=dp[u][i][0][0],dp[u][i][0][0]=0;
g[i][0][1]=dp[u][i][0][1],dp[u][i][0][1]=0;
g[i][1][0]=dp[u][i][1][0],dp[u][i][1][0]=0;
g[i][1][1]=dp[u][i][1][1],dp[u][i][1][1]=0;
}
for(int i=0; i<=min(siz[u],k); i++) {
for(int j=0; j<=min(siz[v],k-i); j++) {
dp[u][i+j][0][0]=get_mod((ll)dp[u][i+j][0][0],(ll)g[i][0][0]*(ll)dp[v][j][0][1]);
dp[u][i+j][0][1]=get_mod((ll)dp[u][i+j][0][1],(ll)g[i][0][0]*(ll)dp[v][j][1][1]+(ll)g[i][0][1]*((ll)dp[v][j][1][1]+(ll)dp[v][j][0][1]));
dp[u][i+j][1][0]=get_mod((ll)dp[u][i+j][1][0],(ll)g[i][1][0]*((ll)dp[v][j][0][0]+(ll)dp[v][j][0][1]));
dp[u][i+j][1][1]=get_mod((ll)dp[u][i+j][1][1],(ll)g[i][1][0]*((ll)dp[v][j][1][0]+(ll)dp[v][j][1][1])+(ll)g[i][1][1]*((ll)dp[v][j][0][0]+(ll)dp[v][j][0][1]+(ll)dp[v][j][1][0]+(ll)dp[v][j][1][1]));
}
}
siz[u]+=siz[v];
}
}
int main() {
n=read();
k=read();
for(int i=1; i<n; i++) {
int u=read(),v=read();
add(u,v);
add(v,u);
}
dfs(1,0);
printf("%d\n",(int)(dp[1][k][0][1]+dp[1][k][1][1])%mod);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?