沝黑。
首先这种统计路径的问题一般联想点分治,然后考虑如何处理经过一个点 \(u\) 的路径。
考虑有一个点 \(p\in u\) 的子树,然后记录路径 \(p\to u\) 和路径 \(u\to p\) 的答案。前者放入一个映射统计,后者存在数组 \(S\) 里面。
最后整体统计,枚举 \(x\in S\),设 \(x\lt M\),统计映射的 \(M-x\) 位置的结果,求一个和。
但是这样可能会有一条路径,从 \(u\) 的一个儿子 \(v\) 的子树来,又到 \(v\) 的子树去。
于是我们考虑分开对每个儿子做一次上述统计子树的算法,然后让 \(u\) 子树的总和减去每个 \(v\) 子树的总和即可。
中间会有把一个多位数和一个数字拼起来的情况,考虑记录下原数的位数,预处理 \(10\) 的次幂以及逆元。
对了,\(M\) 不一定是质数,所以不能用 \(x^{mod-2}\) 的方法求逆元,而是要用 \(\tt exgcd\)。
对了,unordered_map
会被卡,map
已经很够了。
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC target("avx")
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#include<bits/stdc++.h>
using namespace std;
#ifdef ONLINE_JUDGE
static char buf[1000000],*p1=buf,*p2=buf;
#define getchar() p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++
#endif
inline int read(){
register int x = 0;
register char c = getchar();
for(;c < '0' || c > '9';c = getchar());
for(;c >= '0' && c <= '9';c = getchar())
x = x * 10 + (c ^ '0');
return x;
}
#define rg register
#define il inline
#define rep(i,a,b) for(rg int i = (a);i <= (b);++i)
#define Rep(i,a,b) for(rg int i = (a);i >= (b);--i)
#define pb emplace_back
using ll = long long;
const int N = 1e5 + 5;
int n,val,rt,allsiz,siz[N];
ll sum;
int Mod,inv10,pow10[N],powinv10[N];
bitset<N> vis;
vector<pair<int,int>> G[N];
map<int,long long> buc;
vector<pair<ll,int>> num;
il void exgcd(rg int a,rg int b,rg int &x,rg int &y){
if(!b) return x = 1,void(y = 0);
exgcd(b,a % b,y,x);
y -= a / b * x;
}
il int size(rg int u,rg int ft){
int res = 1;
for(auto[v,w] : G[u]) if(!vis[v] && v != ft) res += size(v,u);
return res;
}
il void fndrt(rg int u,rg int ft){
int ans = 0; siz[u] = 1;
for(auto[v,w] : G[u]) if(!vis[v] && v != ft){
fndrt(v,u);
siz[u] += siz[v];
ans = max(ans,siz[v]);
}
ans = max(ans,allsiz - siz[u]);
if(ans < val) val = ans,rt = u;
}
il void dfs(rg int u,rg int ft,rg ll v1,rg ll v2,rg int len){
if(~len) ++buc[v1],num.pb(v2,len);
for(auto[v,w] : G[u]) if(v != ft && !vis[v]){
ll val1 = (1LL * pow10[len + 1] * w % Mod + v1) % Mod;
ll val2 = (v2 * 10 % Mod + w) % Mod;
dfs(v,u,val1,val2,len + 1);
}
}
il ll calc(rg int u,rg int p){
ll cnt = 0; buc.clear(); num.clear();
dfs(u,0,p % Mod,p % Mod,p ? 0 : -1);
for(auto[x,d] : num){
ll v = (Mod - x) * powinv10[d + 1] % Mod;
if(buc.find(v) != buc.end()) cnt += buc[v];
if(!p) cnt += !x;
}
if(!p) if(buc.find(0) != buc.end()) cnt += buc[0];
return cnt;
}
il void solve(rg int u){
vis[u] = 1;
sum += calc(u,0);
for(auto[v,w] : G[u]) if(!vis[v]){
sum -= calc(v,w);
allsiz = size(v,0),val = 1e9,rt = 0,fndrt(v,0);
solve(rt);
}
}
int main(){
n = read(),Mod = read();
rep(i,1,n - 1){
int u,v,w;
u = read(),v = read(),w = read();
++u,++v;
G[u].pb(v,w);
G[v].pb(u,w);
}
int x,y; exgcd(10,Mod,x,y);
inv10 = (x % Mod + Mod) % Mod;
pow10[0] = powinv10[0] = 1;
rep(i,1,n) pow10[i] = 10LL * pow10[i - 1] % Mod;
rep(i,1,n) powinv10[i] = 1LL * inv10 * powinv10[i - 1] % Mod;
allsiz = n,val = 1e9,rt = 0,fndrt(1,0);
solve(rt);
cout << sum << endl;
return 0;
}
标签:Digit,int,ll,Tree,rg,ans,buc,CF715C,Mod
From: https://www.cnblogs.com/zeno6174/p/CF715C.html