感觉自己代码能力太差了,这场比赛的题都调得很痛苦。。
C. Bear and Tree Jumps
对于一棵有根树来说,dfs可以得到每个节点到树根的距离。注意到跳跃距离最大为5,我们可以把距离最多分为五类,同样地,dfs出所有节点到根的距离信息。
我的解法分为两次dfs。第一次dfs可以得到节点1为树根时的距离信息。第二次dfs的目的是“换根”,也就是让每个节点以dfs序作为树根,统计与当前根节点有关的所有pair的总距离。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 200010;
vector<int> E[maxn];
ll dis[maxn][5];
int p[maxn];
ll n,k;
ll ans[maxn];
ll res = 0;
void dfs1(int u,int pre){
dis[u][0] = 1;
int len = E[u].size();
for(int i=0;i<len;i++){
int v = E[u][i];
if(v==pre)continue;
p[v] = u;
dfs1(v,u);
ans[u] += dis[v][0]-1;
ans[u] += ans[v];
for(int i=0;i<k;i++){
dis[u][i] += dis[v][(i+k-1)%k];
}
}
}
void dfs2(int u,int pre){
int len = E[u].size();
ll tmp = ans[u];
if(u!=1)ans[u] += ans[p[u]] + dis[p[u]][0]-1;
res += ans[u];
for(int i=0;i<len;i++){
int v = E[u][i];
if(v==pre)continue;
ans[u] -= dis[v][0]-1;
ans[u] -= ans[v];
for(int i=0;i<k;i++){
dis[u][i] -= dis[v][(i+k-1)%k];
}
for(int i=0;i<k;i++){
dis[v][i] += dis[u][(i+k-1)%k];
}
dfs2(v,u);
for(int i=k-1;i>=0;i--){
dis[v][i] -= dis[u][(i+k-1)%k];
}
for(int i=k-1;i>=0;i--){
dis[u][i] += dis[v][(i+k-1)%k];
}
ans[u] += ans[v];
ans[u] += dis[v][0]-1;
}
ans[u] = tmp;
}
int main(){
cin>>n>>k;
for(int i=1;i<n;i++){
int u,v;
scanf("%d %d",&u,&v);
E[u].push_back(v);
E[v].push_back(u);
}
dfs1(1,0);
dfs2(1,0);
res += n*(n-1);
cout<<res/2<<endl;
return 0;
}
D. Bear and Company
做这题的时候,如果只提示我是dp的话,我也会往区间分割方面想,之前没写过这种类型的dp,确实比较巧妙。因为每个位置的字符都可以往任意地方跑,于是分区间是不管用的。
容易发现除了VK以外的字符都是等效的,定义状态
dp(i,j,k)
表示组成前
i+j+k
个字符有
i
个’V’,
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 200010;
vector<int> E[maxn];
ll dis[maxn][5];
int p[maxn];
ll n,k;
ll ans[maxn];
ll res = 0;
void dfs1(int u,int pre){
dis[u][0] = 1;
int len = E[u].size();
for(int i=0;i<len;i++){
int v = E[u][i];
if(v==pre)continue;
p[v] = u;
dfs1(v,u);
ans[u] += dis[v][0]-1;
ans[u] += ans[v];
for(int i=0;i<k;i++){
dis[u][i] += dis[v][(i+k-1)%k];
}
}
}
void dfs2(int u,int pre){
int len = E[u].size();
ll tmp = ans[u];
if(u!=1)ans[u] += ans[p[u]] + dis[p[u]][0]-1;
res += ans[u];
for(int i=0;i<len;i++){
int v = E[u][i];
if(v==pre)continue;
ans[u] -= dis[v][0]-1;
ans[u] -= ans[v];
for(int i=0;i<k;i++){
dis[u][i] -= dis[v][(i+k-1)%k];
}
for(int i=0;i<k;i++){
dis[v][i] += dis[u][(i+k-1)%k];
}
dfs2(v,u);
for(int i=k-1;i>=0;i--){
dis[v][i] -= dis[u][(i+k-1)%k];
}
for(int i=k-1;i>=0;i--){
dis[u][i] += dis[v][(i+k-1)%k];
}
ans[u] += ans[v];
ans[u] += dis[v][0]-1;
}
ans[u] = tmp;
}
int main(){
cin>>n>>k;
for(int i=1;i<n;i++){
int u,v;
scanf("%d %d",&u,&v);
E[u].push_back(v);
E[v].push_back(u);
}
dfs1(1,0);
dfs2(1,0);
res += n*(n-1);
cout<<res/2<<endl;
return 0;
}