2019 计蒜之道初赛第一场 C.商汤AI园区的n个路口(中等)

    xiaoxiao2023-11-16  154

    链接

    https://nanti.jisuanke.com/t/39262

    题解

    f i j f_{ij} fij表示 i i i号点颜色为 j j j,整棵子树合法的方案数 暴力就是枚举当前点和儿子节点的颜色 他有个条件说边权两两不同,可以发现在 m ∗ m m*m mm g c d gcd gcd矩阵中,每个位置上都对应一个转移 而且每个转移肯定都能对应到矩阵中的某个位置 综上所述,有效的转移只有 O ( m 2 ) O(m^2) O(m2)个 总的复杂度也就降到 O ( n m + m 2 ) O(nm+m^2) O(nm+m2)

    代码

    #include<bits/stdc++.h> #define maxn 1010 #define linf (1ll<<60) #define iinf 0x3f3f3f3f #define eps 1e-8 #define cl(x) memset(x,0,sizeof(x)) #define mod 1000000007ll using namespace std; typedef long long ll; ll read(ll x=0) { int c, f=1; for(c=getchar();!isdigit(c);c=getchar())if(c=='-')f=-f; for(;isdigit(c);c=getchar())x=x*10+c-48; return f*x; } ll N, M, head[maxn], to[maxn], nex[maxn], d[maxn], etot, w[maxn], f[maxn][60], g[maxn]; vector<ll> tran[maxn][maxn]; set<ll> val; void adde(ll a, ll b, ll c){to[++etot]=b;w[etot]=c;nex[etot]=head[a];head[a]=etot;} ll gcd(ll a, ll b){return !b?a:gcd(b,a%b);} void dfs(ll pos, ll pre) { ll s; for(auto p=head[pos];p;p=nex[p]) if(to[p]!=pre) { dfs(to[p],pos); } for(auto c=1;c<=M;c++) { g[pos] += f[pos][c]; g[pos] %= mod; f[pos][c]=1; for(auto p=head[pos];p;p=nex[p]) { if(to[p]==pre)continue; s=g[to[p]]; for(auto son:tran[c][w[p]]) { s-=f[to[p]][son]; } f[pos][c] *= s%mod; f[pos][c] %= mod; } g[pos] += f[pos][c]; g[pos] %= mod; } } int main() { ll a, b, c, i, j, ans(0); N=read(), M=read(); for(i=1;i<N;i++) { a=read(), b=read(), c=read(); adde(a,b,c), adde(b,a,c); val.emplace(c); } for(i=1;i<=M;i++)for(j=1;j<=M;j++) { if( val.find(__gcd(i,j)) != val.end() ) { tran[i][__gcd(i,j)].emplace_back(j); } } dfs(1,0); for(i=1;i<=M;i++) { ans=(ans+f[1][i])%mod; } cout<<(ans+mod)%mod<<endl; return 0; }
    最新回复(0)