模拟赛-树

题意

求满足下面条件有根树的个数。同构的算一种

  • 叶子节点的权值是某个 ai 的倍数
  • 节点的权值为其子树节点的权值之积
  • 根节点权值不超过 n
  • 每个节点要么没有儿子,要么有两个以上儿子

n1010,m8,2ai200

题解

p(x)=1 当且仅当存在一个 i 使得 ai|x,令答案的函数为 f,则

f=p+i2fi=p+f21f

于是则有

f=2f2+p1+p

这里面的除法是迪利克雷逆,乘法是迪利克雷卷积。

首先我们可以 O(LlogL) 的预处理出来 L 之内的 f,f2,(p+1)1 函数的前缀和。

我们考虑怎么算大的范围,首先 p 的前缀和可以用 2m 来暴力容斥,然后 (p+1)1 就是和 p+1 这个函数卷积用杜教筛。

之后 f2 的前缀和也是类似于整除分块的东西,就是 sf2(n)=i=1nsf(ni)f(i) 。然后 f 的前缀和就按照那个式子算

sf(n)=i=1n(1+p)1(ni)×(f2(i)+p(i))

// Siriqwq
#include <bits/stdc++.h>
using std::cin;
using std::cout;
using std::vector;
using std::copy;
using std::reverse;
using std::sort;
using std::get;
using std::unique;
using std::swap;
using std::array;
using std::cerr;
using std::function;
using std::map;
using std::set;
using std::pair;
using std::mt19937;
using std::make_pair;
using std::tuple;
using std::make_tuple;
using std::uniform_int_distribution;
using ll = long long;
namespace qwq {
	mt19937 eng;
	void init(int Seed) {return eng.seed(Seed);}
	int rnd(int l = 1, int r = 1000000000) {return uniform_int_distribution<int> (l, r)(eng);}
}
template<typename T>
inline void chkmin(T &x, T y) {if (x > y) x = y;}
template<typename T>
inline void chkmax(T &x, T y) {if (x < y) x = y;}
template<typename T>
inline T min(const T &x, const T &y) {return x < y ? x : y;}
template<typename T>
inline T max(const T &x, const T &y) {return x > y ? x : y;}
char buf[100000], *bufs, *buft;
#define gc() ((bufs == buft && (buft = (bufs = buf) + fread(buf, 1, 100000, stdin))), bufs == buft ? -1 : *bufs++)
template<typename T>
inline void read(T &x) {
	x = 0;
	bool f = 0;
	char ch = gc();
	while (!isdigit(ch)) f = ch == '-', ch = gc();
	while (isdigit(ch)) x = x * 10 + ch - '0', ch = gc();
	if (f) x = -x;
}
inline void reads(char *s) {
	char ch = gc();
	while (isspace(ch)) ch = gc();
	while (!isspace(ch) && ch != EOF) *(s++) = ch, ch = gc();
	*s = 0;
	return;
}
template<typename T, typename ...Arg>
inline void read(T &x, Arg &... y) {
	read(x);
	read(y...);
}
#define O(x) cerr << #x << " : " << x << '\n'
const double Pi = acos(-1);
const int MAXN = 262144, MOD = 1e9 + 7, inv2 = (MOD + 1) / 2, I32_INF = 0x3f3f3f3f;
const long long I64_INF = 0x3f3f3f3f3f3f3f3f;
auto Ksm = [] (int x, int y) -> int {
	if (y < 0) {
		y %= MOD - 1;
		y += MOD - 1;
	}
	int ret = 1;
	for (; y; y /= 2, x = (long long) x * x % MOD) if (y & 1) ret = (long long) ret * x % MOD;
	return ret;
};
auto Mod = [] (int x) -> int {
	if (x >= MOD) return x - MOD;
	else if (x < 0) return x + MOD;
	else return x;
};
template<const int N_num, const int M_num>
struct Graph {
	int H[N_num];
	struct Edge {int to, lac;} e[M_num];
	inline void add_edge(int x, int y) {e[*H] = {y, H[x]};H[x] = (*H)++;}
	inline void init() {memset(H, -1, sizeof H);*H = 0;}
};
#define go(x, y) for (int i = x.H[y], v; (v = x.e[i].to) && ~i; i = x.e[i].lac)
inline int ls(int k) {return k << 1;}
inline int rs(int k) {return k << 1 | 1;}
using ull = unsigned long long;
void add(int &x, int y) {if ((x += y) >= MOD) x -= MOD;}
const int MAXM = 2e6 + 10;
ll N;
int M, A[10], sp[MAXM], sip1[MAXM], sf2[MAXM], sf[MAXM];
ll prod[256];
inline ll gcd(ll x, ll y) {
	for (; y; x %= y, swap(x, y));
	return x;
}
std::unordered_map<ll, int> m_sp, m_sip1, m_sf, m_sf2;
int calc_sp(ll n) {
	if (n < MAXM) return sp[n];
	if (m_sp.count(n)) return m_sp[n];
	int &res = m_sp[n] = 0;
	for (int i = 1; i < 1 << M; ++i) add(res, ((__builtin_popcount(i) & 1) ? 1LL : MOD - 1LL) * (n / prod[i] % MOD) % MOD);
	return res;
}
int calc_sip1(ll n) {
	if (n < MAXM) return sip1[n];
	if (m_sip1.count(n)) return m_sip1[n];
	// O(n);
	int &res = m_sip1[n] = 1;
	for (ll l = 2, r; l <= n; l = r + 1) {
		r = n / (n / l);
		add(res, (ll) Mod(calc_sp(l - 1) - calc_sp(r)) * calc_sip1(n / l) % MOD);
	}
	return res;
}
int calc_sf(ll n);
int calc_sf2(ll n) {
	if (n < MAXM) return sf2[n];
	if (m_sf2.count(n)) return m_sf2[n];
	int &res = m_sf2[n] = 0;
	// O(n);
	for (ll l = 2, r; l <= n; l = r + 1) {
		r = n / (n / l);
		add(res, (ll) Mod(calc_sf(r) - calc_sf(l - 1)) * calc_sf(n / l) % MOD);
	}
	return res;
}
int calc_sf(ll n) {
	// O(n);
	if (n < MAXM) return sf[n];
	if (m_sf.count(n)) return m_sf[n];
	int &res = m_sf[n] = 0;
	for (ll l = 2, r; l <= n; l = r + 1) {
		r = n / (n / l);
		add(res, (ll) Mod(2 * Mod(calc_sf2(r) - calc_sf2(l - 1)) % MOD + Mod(calc_sp(r) - calc_sp(l - 1))) * calc_sip1(n / l) % MOD);
	}
	return res;
}
int main() {
	freopen("tree.in", "r", stdin);
	freopen("tree.out", "w", stdout);
	// std::ios::sync_with_stdio(0);
	// cout << std::fixed << std::setprecision(8);
	// cin.tie(0);
	// cout.tie(0);
	qwq::init(20050112);
	read(N, M);
	for (int i = 1; i <= M; ++i) read(A[i]);
	sort(A + 1,  A + 1 + M);
	M = unique(A + 1, A + 1 + M) - A - 1;
	for (int i = 1; i <= M; ++i) for (int j = A[i]; j < MAXM; j += A[i]) sp[j] = 1;
	sip1[1] = 1;
	for (int i = 1; i < MAXM; ++i) for (int j = i + i; j < MAXM; j += i) sip1[j] = Mod(sip1[j] - sip1[i] * sp[j / i]);
	for (int i = 1; i < MAXM; ++i) {
		for (int j = 1; j * i < MAXM; ++j) {
			add(sf[i * j], (2LL * sf2[i] + sp[i]) * sip1[j] % MOD);
			if (j <= i) add(sf2[i * j], (i == j ? 1LL : 2LL) * sf[i] * sf[j] % MOD);
		}
	}
	for (int i = 1; i < MAXM; ++i) add(sp[i], sp[i - 1]), add(sip1[i], sip1[i - 1]), add(sf[i], sf[i - 1]), add(sf2[i], sf2[i - 1]);
	for (int i = 1; i < 1 << M; ++i) {
		prod[i] = 1;
		for (int j = 0; j < M; ++j) if ((i >> j) & 1) prod[i] = prod[i] / gcd(A[j + 1], prod[i]) * A[j + 1];
	}
	// O(sip1[8]);
	printf("%d\n", calc_sf(N));
	// cout << (-3 / 2);
	cerr << ((double) clock() / CLOCKS_PER_SEC) << '\n';
	return (0-0);
}

posted @   siriehn_nx  阅读(110)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示