VK Cup 2017 - Round 1

感觉自己代码能力太差了,这场比赛的题都调得很痛苦。。

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’,j个’K’和 k <script type="math/tex" id="MathJax-Element-207">k</script>个其他字符需要的最小次数,再加一维表示最后一个字符是否是’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;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值