yww y recuento de bloques conectados
Análisis
Restricciones adicionales del tema de observación, \ (s1 | a_i, a_i | s2 \) ; \ (\ nexists i> 1, i ^ 2 | s2 \)
Esto significa que para cada factor de \ (s2 \) , el número de ocurrencias es \ (1 \)
Si \ (a_i, s1, s2 \ ) eliminó todos \ (GCD (S1, S2) \) , entonces todos los factores restantes de acuerdo con las \ (a_i \) marca un estado binario \ (C_i \)
Luego, en el bloque Unicom seleccionado, todos los factores que han cumplido las condiciones son \ (\ {C_u \ xor \ C_v | (u, v) \ en E, u \ in V ', v \ in V' \} \) De o
Porque si hay una diferencia entre \ (C_u \) y \ (C_v \) \ (\ Leftrightarrow \), significa que este factor ha aparecido en dos casos de \ (0,1 \) , es decir, satisface \ ( Limitaciones de \ text {GCD} \) y \ (\ text {LCM} \)
En este momento, tenemos dos formas de calcular (recomendación personal Solution2 Kazakhstan)
Deje que el conjunto de factores primos de \ (n \) sea \ (p \)
Solución1: FWT
Para el punto de transferir directamente \ (dp \) \ (dp [u] [S] \) significa que el punto más alto actual es \ (u \) , y el conjunto de factores que satisfacen la condición es el número de soluciones de \ (S \)
\ (dp [u] [i | j] = dp [u] [i] \ cdot dp [v] [j] \)
Debido a la operación OR, puede usar el prefijo de orden superior y / \ (FWT \) o convolución
Sin optimización, la complejidad de ambos enfoques es \ (O (n | p | 2 ^ {| p |}) \)
Pero no tiene que \ (\ text {FWT} \) en el pasado \ (\ text {FWT} \) volver siempre, por lo que la complejidad después de guardar es \ (O (n \ cdot 2 ^ {| p |}) \)
El código no es mío (@ 神仙 Rtx)
#include <bits/stdc++.h>
#define rep(i, a, b) for(int i(a), i##_END(b); i <= i##_END; i++)
#define drep(i, a, b) for(int i(a), i##_END(b); i >= i##_END; i--)
using namespace std;
const int maxn = 1010, mod = 1e9+7;
typedef long long ll;
vector<int> e[maxn];
int n, pr[60], cnt, v[60], hs[maxn];
ll a[maxn], s1, s2, f[maxn][(1<<15)+10], ans[(1<<15)+10];
inline void ins(ll &x, ll y) { x = (x + y >= mod ? x + y - mod : x + y); }
void init(int N) {
rep(i, 2, N) {
if(!v[i]) pr[++cnt] = i;
for(int j = 1; j <= cnt && i * pr[j] <= N; ++j)
v[i * pr[j]] = 1;
}
}
void rfwt(ll *p, int N) {
for(int mid = 1; mid < N; mid <<= 1)
for(int i = 0; i < N; i += (mid << 1))
for(int j = 0; j < mid; ++j) ins(p[i + j + mid], mod - p[i + j]);
}
void dfs(int x, int pa) {
rep(i, 0, (1<<cnt)-1) f[x][i] = 1;
rep(i, 0, e[x].size() - 1) if(e[x][i] != pa) {
int y = e[x][i];
dfs(y, x);
int diff = hs[x] ^ hs[y];
for(int s = diff; s < (1<<cnt); s = (s+1)|diff)
ins(f[x][s], f[x][s] * f[y][s] % mod);
}
rep(i, 0, (1<<cnt)-1) ins(ans[i], f[x][i]);
}
int main() {
scanf("%d%lld%lld", &n, &s1, &s2), s2 /= s1;
int x, y;
rep(i, 1, n) scanf("%lld", &a[i]), a[i] /= s1;
rep(i, 2, n) scanf("%d%d", &x, &y), e[x].push_back(y), e[y].push_back(x);
init(50);
rep(i, 1, n) rep(j, 1, cnt) if(a[i] % pr[j] == 0) hs[i] |= (1<<(j-1));
dfs(1, 0);
rfwt(ans, 1<<cnt); // 最后FWT回来就可以了
int mx = 0;
rep(i, 1, cnt) if(s2 % pr[i] == 0) mx |= (1<<(i-1));
printf("%lld\n", ans[mx]);
return 0;
}
Solución2: Tolerancia
Enumerar el conjunto de factores que no satisfacen la condición es \ (S \) , entonces debe haber \ ((C_u \ xor \ C_v) \ y S = {\ empty} \)
\ (O (n) \ \ \ text {dp} \) La solución puede ser la misma que la anterior, pero se omite la segunda dimensión
Entonces es simple paridad.
Como puede ver, la complejidad es \ (O (n \ cdot 2 ^ {| p |}) \) , que está llena
const int N=1e3+10;
int n,C[N],fac[N],fc;
ll A,B,g;
ll gcd(ll a,ll b){ return b==0?a:gcd(b,a%b); }
vector <int> G[N];
int S;
ll dp[N];
void dfs(int u,int f) {
dp[u]=1;
for(int v:G[u]) if(v!=f) {
dfs(v,u);
if(((C[u]^C[v])&S)==0) dp[u]=(dp[u]+dp[u]*dp[v])%P; // 按照限制dp
}
}
int main(){
n=rd(),A=rd<ll>(),B=rd<ll>(),g=gcd(A,B);
A/=g,B/=g;
rep(i,2,50) if(B%i==0) B/=i,fac[fc++]=i; // 这些是预处理因数集合
rep(i,1,n) {
ll x=rd<ll>()/g;
rep(j,0,fc-1) if(x%fac[j]==0) C[i]|=1<<j;
}
rep(i,2,n) {
int u=rd(),v=rd();
G[u].pb(v),G[v].pb(u);
}
ll ans=0;
for(S=0;S<(1<<fc);++S) { // 枚举不合法的状态
int cnt=0;
rep(i,0,fc-1) if(S&(1<<i)) cnt^=1;
dfs(1,0);
rep(i,1,n) if(cnt) ans-=dp[i];
else ans+=dp[i]; // 偶加奇减
}
ans=(ans%P+P)%P;
printf("%lld\n",ans);
}