就先写了CD两个题orz
C- The Tag Game
题意在一棵树上AB玩追逐游戏,A开始时在节点1,B在节点X
两人轮流操作,B先手,每次操作可以选择移动到相邻格子或者原地不动
A想要尽快抓到B而B想尽量逃的久一点,问多少轮【B操作一下A操作一下是两轮】后B会被A抓到
答案就是A操作的数目乘2,我们把节点1当成根,那么B能逃到的离根最远的节点就是他被抓到的定点
但B也可以向根移动一定的步数,再走到别的子树来使得被抓到的节点尽量的远
计算下这个能向上移动的距离d就等于 节点X的深度-1再整除2
那么我们DFS一下用一个dep记录节点深度,depp节点记录当前节点最多还能向下走几步,fa记录节点的父节点
用深度算出向上移动步数,转移到目标节点x'后最远的距离就等于dep[x']+depp[x']
没啥难度就是怎么优雅的A题的问题。。。。
#include<bits/stdc++.h>
#define maxn 200009
using namespace std;
struct ed{
int v,next;
}edge[2*maxn];
int head[maxn],x,n,tot,dep[maxn],fa[maxn],depp[maxn];
void addedge(int u,int v){
edge[tot].v=v;
edge[tot].next=head[u];
head[u]=tot;
tot++;
}
int dfs(int u,int v){
dep[v]=dep[u]+1;
fa[v]=u;
for (int i=head[v];i!=-1;i=edge[i].next){
if (edge[i].v==u)continue;
int lin2dep=dfs(v,edge[i].v);
if (lin2dep>depp[v])depp[v]=lin2dep;
}
depp[v]+=1;
return depp[v];
}
int main(){
memset(head,-1,sizeof(head));
memset(depp,-1,sizeof(depp));
tot=0;
scanf("%d%d",&n,&x);
int u,v;
for (int i=1;i<n;i++){
scanf("%d%d",&u,&v);
addedge(u,v);
addedge(v,u);
}
dep[0]=-1;
dfs(0,1);
//for (int i=1;i<=n;i++)printf("* %d %d\n",dep[i],depp[i]);
int cnt=(dep[x]-1)/2;
int wei=x;
while(cnt--){
wei=fa[wei];
}
printf("%d\n",(depp[wei]+dep[wei])*2);
return 0;
}
D-Two Melodies
题意给一个序列a[i],你要其中找两个不相交的子序列,使得两个子序列都满足melody条件,且两个子序列长度和最大,要求输出最长的长度值
melody条件就是序列中的前后两项满足要么两个数差为1,要么差为7的倍数
DP题,神仙DP你们怎么什么都会做orz
首先因为数据范围5000所以可以用n^2的二维DP来做
我们定义dp[i][j]表示第一个子序列末尾是i,第二个子序列末尾是j,两个子序列不重合情况下序列的最大长度,
那么我们在更新时怎么保持两个子序列不相交呢?
注意到一点,dp[ i ][ j ] 和dp[ j ][ i ]值是相等的,
那么我们采用枚举 i 更新 j ,并且 j 从i +1开始更新的方法就能保证不重复了【而且每次前头dp[i][j] j<i的部分都是已经求了的】
因为在更新dp[i][j]时,保证 j>i 那么我们新加进来的a[j]肯定不可能在i的序列中出现过
那么考虑dp怎么转移
我们更新 dp[i][j], 那么一种状态是 dp[i][0] 然后把 a[j]放到第二个首部
一种状态是 从 a[j]-1,a[j]+1 转移过来
一种状态是从某个和a[j]相差7的倍数的数转移过来 【a[j]%7 == a[ j']%7】
然后为了减少复杂度我们维护一个maxmod 和 maxnum 数组 存%7 和 相差1 状况下最大的长度数值,
每次更新dp[i][j]后更新数组和dp[j][i];
详细看代码
#include<bits/stdc++.h>
using namespace std;
const int maxm =5e3+10;
const int maxn =1e5+10;
int a[maxm];
int maxmod[8];
int dp[maxm][maxm],maxnum[maxn];
int main(){
int n;
scanf("%d",&n);
for (int i=1;i<=n;i++)scanf("%d",&a[i]);
memset(dp,0,sizeof(dp));
int ans=0;
for (int i=0;i<=n;i++){
//维护最大值数组
memset(maxmod,0,sizeof(maxmod));
memset(maxnum,0,sizeof(maxnum));
for (int j=1;j<=i;j++){
maxmod[a[j]%7]=max(maxmod[a[j]%7],dp[i][j]);
maxnum[a[j]]=max(maxnum[a[j]],dp[i][j]);
}
for (int j=i+1;j<=n;j++){
dp[i][j]=max(dp[i][0]+1,dp[i][j]);
dp[i][j]=max(maxmod[a[j]%7]+1,dp[i][j]);
dp[i][j]=max(maxnum[a[j]-1]+1,dp[i][j]);
dp[i][j]=max(maxnum[a[j]+1]+1,dp[i][j]);
maxmod[a[j]%7]=max(maxmod[a[j]%7],dp[i][j]);
maxnum[a[j]] =max(maxnum[a[j]] ,dp[i][j]);
dp[j][i]=dp[i][j];
ans =max(ans,dp[i][j]);
}
}
printf("%d\n",ans);
return 0;
}