树形DP
P3565 [POI2014] HOT-Hotels
:
先说一下我想到的
首先不难发现,如果三个点两两距离相等,那么一定存在一个中心点,使得中心点到这三个点的距离相等。
枚举每一个点作为中心节点,然后从它开始将整个树
如何计算它?可以考虑增量法。设
void dfs(int x,int fa,int d){
if(p[cnt].size()<d)
p[cnt].push_back(1);
else
++p[cnt][d-1];
for(int i=head[x];i;i=nxt[i])
if(ver[i]!=fa)
dfs(ver[i],x,d+1);
}
void work(int x){
cnt=0;
for(int i=head[x];i;i=nxt[i]){
++cnt;p[cnt].clear();
dfs(ver[i],x,1);
}
bool ok=1;
for(int i=1;;++i){
int s=0,s2=0,s3=0;
for(int j=1;j<=cnt;++j){
if(p[j].size()<i)
continue;
s3+=p[j][i-1]*s2;
s2+=p[j][i-1]*s;
s+=p[j][i-1];
}
if(!s3) break;
ans+=s3;
}
}
void solve(int x){
vis[x]=1;sum=1e9;
work(x);
for(int i=head[x];i;i=nxt[i])
if(!vis[ver[i]])
solve(ver[i]);
}
其实这个题是可以优化到
设
状态转移方程:
如果我们钦定一个儿子,那么
我们进行长链剖分,每次钦定从重儿子直接转移,那么我们还需要从轻儿子进行转移。
那么,复杂度拆分成两个部分:直接从重儿子转移
P4516 潜入行动
2023.6.18拷逝T4
树形背包好题。
设
状态转移方程:
①:
②:
③:
如果
④:
如果
#include<iostream>
#include<cstdio>
using namespace std;
const int mod=1e9+7,l=1e5+5;
int n,k,a,b,tot,head[l<<1],ver[l<<1],nxt[l<<1];
int dp[l][105][2][2],tmp[l][2][2],siz[l];
void add(int x,int y){
nxt[++tot]=head[x];head[x]=tot;ver[tot]=y;
}
void dfs(int x,int fa){
siz[x]=dp[x][0][0][0]=dp[x][1][1][0]=1;
for(int t=head[x];t;t=nxt[t]){
int v=ver[t];
if(v!=fa){
dfs(v,x);
for(int i=0;i<=min(k,siz[x]);++i){
tmp[i][0][0]=dp[x][i][0][0];dp[x][i][0][0]=0;
tmp[i][0][1]=dp[x][i][0][1];dp[x][i][0][1]=0;
tmp[i][1][0]=dp[x][i][1][0];dp[x][i][1][0]=0;
tmp[i][1][1]=dp[x][i][1][1];dp[x][i][1][1]=0;
}
for(int i=0;i<=min(k,siz[x]);++i)
for(int j=0;j<=min(k-i,siz[v]);++j){
dp[x][i+j][0][0]=(dp[x][i+j][0][0]+1ll*tmp[i][0][0]*dp[v][j][0][1]%mod)%mod;
dp[x][i+j][0][1]=(dp[x][i+j][0][1]+1ll*tmp[i][0][1]*(dp[v][j][0][1]+dp[v][j][1][1])%mod)%mod;
dp[x][i+j][0][1]=(dp[x][i+j][0][1]+1ll*tmp[i][0][0]*dp[v][j][1][1]%mod)%mod;
dp[x][i+j][1][0]=(dp[x][i+j][1][0]+1ll*tmp[i][1][0]*(dp[v][j][0][0]+dp[v][j][0][1])%mod)%mod;
dp[x][i+j][1][1]=(dp[x][i+j][1][1]+1ll*tmp[i][1][0]*(dp[v][j][1][1]+dp[v][j][1][0])%mod)%mod;
dp[x][i+j][1][1]=(dp[x][i+j][1][1]+1ll*tmp[i][1][1]*(1ll*(dp[v][j][0][0]+dp[v][j][0][1])+1ll*(dp[v][j][1][0]+dp[v][j][1][1]))%mod)%mod;
}
siz[x]+=siz[v];
}
}
return ;
}
int main(){
scanf("%d%d",&n,&k);
for(int i=1;i<n;++i)
scanf("%d%d",&a,&b),add(a,b),add(b,a);
dfs(1,0);
printf("%d\n",(dp[1][k][1][1]+dp[1][k][0][1])%mod);
fclose(stdin);fclose(stdout);
return 0;
}
相似题:
保安站岗:完全就是这道题的弱化版。
消防局的设立:略难,需要注意把所有情况考虑全面,尤其是
设
设
设
设
设
设
void dfs(int x,int fa){
f[x][3]=1;f[x][1]=f[x][2]=1e9;
for(int i=head[x];i;i=nxt[i])
if(ver[i]!=fa){
dfs(ver[i],x);
f[x][2]=min(f[x][2]+min(f[ver[i]][2],min(f[ver[i]][1],min(f[ver[i]][3],f[ver[i]][0]))),min(f[x][1],min(f[x][0],min(f[x][4],f[x][5])))+f[ver[i]][3]);
f[x][1]=min(f[x][1]+min(f[ver[i]][1],f[ver[i]][2]),f[x][0]+f[ver[i]][2]);
f[x][5]=min(f[x][5]+min(f[ver[i]][1],min(f[ver[i]][2],f[ver[i]][0])),f[x][0]+f[ver[i]][2]);
f[x][0]+=f[ver[i]][1];
f[x][4]+=f[ver[i]][0];
f[x][3]+=min(f[ver[i]][0],min(f[ver[i]][1],min(f[ver[i]][2],min(f[ver[i]][3],min(f[ver[i]][4],f[ver[i]][5])))));
}
}
P3942 将军令 :上一题的加强版,即照亮范围不再是
P3554 [POI2013] LUK-Triumphal arch
显然答案具有单调性,所以二分小
设
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】