yww y recuento de bloques conectados

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);
}

Supongo que te gusta

Origin www.cnblogs.com/chasedeath/p/12743738.html
Recomendado
Clasificación