考试期间
考试开始的时候花了小半个小时用来读题
t1是很有想法的,一眼就有了动归的思路,
t2看完第一问觉得很眼熟,就是1 2 4 8。。。但我并不记得我学过
t3是图,想到了集训时候讲的lac,想用。
八点半左右开始码代码,先写的t1,然后就一口气写了一个半小时
在状态的设置上出错了,导致我换了一种三维的方法重新码
调试到还有半个小时才恋恋不舍地撒手,最后也没做出来
t2就会第一问,第二问一毫无头绪
手推了一下10以内,想得3分的,结果还错了一个点
t3本来打算lca,然后一一枚举一边,代码实现出错了,调试时间也被自己耗完了。。
正解
t1
错的状态: dp[i][j] 表示 前 i 个检查点,跳过了 j 个 的最优值
参考导弹拦截的定义方式,必须要记录当前在哪个检查点。
修改状态的定义:dp[i][j] 表示 当前位于 第 i 个 检查点, 跳过了 j个 的最优值。
状态转移: dp[i][j] = min( dp[i-k-1][j-k] + dis(i-k-1,i) )
t2
第一问没问题
log2(n)+1即可
第二问用dfs或者dp都可做
t3
需要推导一个公式
把距离给分一下,就变成了两部分,用乘法原理
ans+=f[now][k-j]*f[edge[i].y][j-1];//到now距离为k-j的所有点,到edge[i].y距离为j-1的所有点
再更新一下就行
f[now][j+1]+=f[edge[i].y][j];
dfs都40分,下次不确定还是先打暴力吧
#include<bits/stdc++.h>
using namespace std;
int n,k;
int x,y;
struct edge
{
int y,nxt;
}Edge[50010*2];
int Link[50010],cnt;
void Insert(int x,int y)
{
Edge[++cnt].nxt=Link[x];
Link[x]=cnt;
Edge[cnt].y=y;
}
int ans;
void dfs(int x,int fa,int dep)
{
if(dep==k)
{
ans++;
return ;
}
for(int i=Link[x];i;i=Edge[i].nxt)
{
int y=Edge[i].y;
if(y==fa)
continue;
dfs(y,x,dep+1);
}
}
int main()
{
freopen("distance.in","r",stdin);
freopen("distance.out","w",stdout);
cin>>n>>k;
for(int i=1;i<n;i++)
{
cin>>x>>y;
Insert(x,y);
Insert(y,x);
}
for(int i=1;i<=n;i++)
dfs(i,0,0);
cout<<ans/2;
return 0;
}
反思
1.时间分配不敢死磕一道题,不然调试时间都没有
2.下次可以坚定一下自己想法,别乱改
3.先打出暴力再说 不然分肯定低