比赛 round 2『计协冻梨桐难霍』 评测结果 AAAAAAAAAAAAAAAAA
题目名称 森林还是基环树? 最终得分 100
用户昵称 darkMoon 运行时间 1.343 s
代码语言 C++ 内存使用 10.68 MiB
提交时间 2024-11-22 08:17:30
显示代码纯文本
#include<bits/stdc++.h>
#define int long long
#define fi first
#define se second
#define mp make_pair
using namespace std;
auto mread = [](){int x;scanf("%lld", &x);return x;};
const int N = 1505, M = 2505, MOD = 1e9 + 7;
int n = mread(), m = mread(), X = mread(), Y = mread(), fa[N], d[N][N], s[N][M], g[M];
vector<pair<int, int> > v[N];
int findfa(int x){
    if(x == fa[x]){
        return x;
    }
    return fa[x] = findfa(fa[x]);
}
void dfs(int x, int fa, int root, int dis){
    int y;
    d[root][x] = dis;
    for(auto t : v[x]){
        y = t.fi;
        if(y == fa){
            continue;
        }
        dfs(y, x, root, dis + t.se);
    }
    return;
}
vector<vector<pair<int, int> > > v2;
int f[M];
int ksm(int x, int k){
    int ans = 1, now = x;
    while(k){
        if(k & 1){
            ans = ans * now % MOD;
        }
        now = now * now % MOD;
        k >>= 1;
    }
    return ans;
}
signed main(){
    for(int i = 1; i <= n; i ++){
        fa[i] = i;
    }
    for(int i = 1, x, y, z; i <= m; i ++){
        cin >> x >> y >> z;
        v[x].push_back(mp(y, z));
        v[y].push_back(mp(x, z));
        fa[findfa(x)] = findfa(y);
    }
    for(int i = 1; i <= n; i ++){
        dfs(i, 0, i, 0);
    }
    for(int i = 1; i <= n; i ++){
        for(int j = i + 1; j <= n; j ++){
            if(findfa(i) == findfa(j) && d[i][j] < Y){
                s[findfa(i)][d[i][j]] += 2;
            }
        }
    }
    int sum = 0;
    {
        bool e[N] = {0};
        for(int i = 1; i <= n; i ++){
            if(e[findfa(i)] == 0){
                e[findfa(i)] = 1;
                sum ++;
            }
        }
    }
    Y -= X * sum;
    for(int i = 1; i <= n; i ++){
        vector<pair<int, int> > tmp;
        for(int j = 0; j < Y; j ++){
            if(s[i][j]){
                tmp.push_back(mp(j, s[i][j]));;
            }
        }
        if(tmp.size()){
            v2.push_back(tmp);
        }
    }
    f[0] = 1;
    for(auto t : v2){
        for(int j = Y - 1; j >= 0; j --){
            for(auto k : t){
                if(j + k.fi < Y){
                    g[j + k.fi] = (g[j + k.fi] + f[j] * k.se % MOD) % MOD;
                }
            }
        }
        for(int j = 0; j < Y; j ++){
            f[j] = g[j];
            g[j] = 0;
        }
    }
    int sum1 = 0, sum2 = 0;
    // sum: 农场个数        sum1: 所有赛道长度和        sum2: 不合法赛道长度和
    for(int i = 0; i < Y; i ++){
        sum2 = (sum2 + f[i] * (i + X * sum) % MOD) % MOD;
    }
    {
        int tmp = 1, s2[n + 5] = {0};
        for(int i = 1; i <= n; i ++){
            s2[findfa(i)] ++;
        }
        for(int i = 1; i <= n; i ++){
            if(s2[i]){
                tmp = tmp * (s2[i] * (s2[i] - 1) % MOD) % MOD;
            }
        }
        for(int i = 1; i <= n; i ++){
            for(int j = i + 1; j <= n; j ++){
                if(findfa(i) == findfa(j)){
                    int t2 = tmp * ksm(s2[findfa(i)] * (s2[findfa(i)] - 1) % MOD, MOD - 2) % MOD;
                    sum1 = (sum1 + 2ll * t2 % MOD * d[i][j] % MOD) % MOD;
                }
            }
        }
        sum1 = (sum1 + X * sum * tmp % MOD) % MOD;
    }
    int ans = (sum1 - sum2 + MOD) % MOD;
    for(int i = 2; i <= (sum - 1); i ++){
        ans = ans * i % MOD;
    }
    ans = ans * ksm(2, MOD - 2) % MOD;
    printf("%lld", ans);
    return 0;
}