2019牛客國慶集訓派對day1-2019(I)

題目連接

圖片

核心:

感受又是一個樹形dp. dp[rt][k]:表示以rt爲根的樹中,到rt距離爲%2019=k的個數。 更新方式:來了一顆新樹x, rt這邊到rt距離爲d1的點,與x這邊到x距離爲d2的點,若(d1+d2+val)%2019==0, 則ans+=dp[rt][d1]*dp[val][d2],val表示rt與x之間的距離; 以後更新dp[rt][d], dp[rt][(d+val)%2019]+=dp[rt][d]

總結:

先求ans, 再更新dp[rt][d]

代碼

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
struct node {
    int to;
    int val;
};
const int N=2e4+3;
const int mod=2019;
int d[N][mod+3];
bool vis[N];
vector<node> g[N];
int n; LL ans;
void dfs(int rt) {
    d[rt][0]+=1; // 重要
    vis[rt]=1;
    for (int i=0;i<g[rt].size();i++) {
        int nxt=g[rt][i].to;
        int val=g[rt][i].val;
        if(vis[nxt]) continue;
        dfs(nxt);
        for(int k=0;k<mod;k++) {
            int x=(mod*2-k-val)%mod;
            ans+=d[nxt][x]*d[rt][k]; // 統一全部的距離是通過rt與nxt的一條路徑
        }
        for(int k=0;k<mod;k++)
            d[rt][(k+val)%mod]+=d[nxt][k];
    }
    // 形式二 d[rt][0]+=1;
    //       ans+=d[rt][0]-1;
}
int main()
{
    while(~scanf("%d",&n)) {
        ans=0;
        memset(d,0,sizeof(d));
        memset(vis,0,sizeof(vis));
        for (int i=0;i<N;i++)
            g[i].clear();
        for (int i=1;i<n;i++) {
            int a,b,c;
            scanf("%d %d %d",&a,&b,&c);
            // 個人傻逼錯誤
            // if(a<b) swap(a,b); 這樣會改變圖的形狀
            node tmp={b,c}; g[a].push_back(tmp);
            tmp.to=a;       g[b].push_back(tmp);
        }
        dfs(1);
        printf("%lld\n",ans);
    }
    return 0;

}
相關文章
相關標籤/搜索