7 7 7 月 28 28 28 日 d p dp dp 训练总结
时间安排
考试时间:8点到10点
8 : 00 ∼ 9 : 00 8:00\sim9:00 8:00∼9:00 : 最开始用十几分钟把三道题看了一遍,发现好像只有 T 1 T1 T1 有思路;所以 T 1 T1 T1 磕了快一个小时。
9 : 00 ∼ 9 : 40 9:00\sim9:40 9:00∼9:40 : 开始写 T 2 T2 T2,原本想写 d p dp dp 的但是怎么也想不到状态转移方程式,然后就开始手算,结果发现手算也不简单,到最后就打表写上去了 ≤ 10 \leq10 ≤10 的情况。
9 : 40 ∼ 10 : 00 9:40\sim10:00 9:40∼10:00 : T 3 T3 T3 没想到 d p dp dp 的方法然后就写了个邻接表和大法师骗了20分
总分: 0 + 30 + 20 = 50 0+30+20=50 0+30+20=50;
正解 & \& & 总结
T 1 T1 T1 题目链接
考试的时候思路和转移方程都差不多跟答案一样,就是在处理如果前面有跳过的检查站的时候下一次计算时要用跳过的检查站之前的横纵坐标,本来加一重循环就能解决问题,但是我却一直想定义变量去记录,导致思路都乱了,最后抱玲。
转移方程式如下:
long long dp[N][N];//表示前i个检查点略过j个检查点的最小距离;
memset(dp,inf,sizeof(dp));
dp[1][0]=0;
for(int i=1;i<=n;i++)
for(int j=0;j<i&&j<=k;j++)
for(int l=0;l<=j;l++)//枚举中间跳过了几个检查站
dp[i][j]=min(dp[i][j],dp[i-l-1][j-l]+abs(a[i-l-1].x-a[i].x)+abs(a[i-l-1].y-a[i].y));
T 2 T2 T2 题目链接
捯饬了好长时间还是只是手算出来了 30 % 30\% 30% 的部分分
第一问其实用二进制拆分就能解出来所以只需要输出 ⌈ l o g 2 ( n ) ⌉ \lceil log2(n) \rceil ⌈log2(n)⌉ 就行了;
第二问用大法师和 d p dp dp 都能写
d p dp dp 做法:
dp[1][1][1]=1;
for(int i=1;i<=cnt;i++)
for(int j=1;j<=n;j++)
for(int k=1;k<=n;k++)
if(dp[i][j][k])
for(int l=j+1;l<=k+1;l++)
dp[i+1][l][min(k+l,n)]+=dp[i][j][k];
for(int j=1;j<=n;j++)
ans+=dp[cnt][j][n];
d f s dfs dfs 做法
void dfs(int x,int sum,int k)
{
if(k==tot)
{
if(sum>=n) ans++;
return;
}
int l=sum;
for(int j=k+1;j<=tot;j++)
{
l=l*2+1;
}
if(l<n) return;
for(int j=x+1;j<=sum+1;j++)
{
dfs(j,sum+j,k+1);
}
}
dfs(1,1,1);
T 3 T3 T3 题目链接
当时写的 d f s dfs dfs 时间比较仓促,没有考虑那么多,其实正解就是把树上的路径在 d p dp dp 中看作两段路然后根据乘法原理加到 a n s ans ans 上就行了
代码:
void dfs(int x,int fa)
{
dp[x][0]=1;
for(int i=Link[x];i;i=Edge[i].nxt)
{
int y=Edge[i].y;
if(y==fa) continue;
dfs(y,x);
for(int j=1;j<=k;j++)
ans+=(dp[x][k-j]*dp[y][j-1]);
for(int j=1;j<=k;j++) dp[x][j]+=dp[y][j-1];
}
}
dfs(1,0);