洛谷P2429 制杖题 题解
题目链接:P2429 制杖题
题意:
求不大于 $m$ 的、质因数集与给定质数集有交集的自然数之和。
输入格式:
第一行,两个整数 $n, m$。
第二行,$n$ 个整数,表示质数集内的元素 $p_i$。
输出格式:
一个整数,表示答案,对 $376544743$ 取模。
数据范围:
测试点编号 规模 $1 \sim 3$ $n m \le {10}^7$ $4 \sim 5$ $n \le 2$,$m \le {10}^9$ $6 \sim 7$ $n \le 20$,$m \le {10}^8$ $8 \sim 10$ $n \le 20$,$m \le {10}^9$ 对于 $100 \%$ 的数据,$1 \le n \le 30$,$1 \le m \le {10}^9$。
数据范围可能有点令人迷惑,我猜它是指测试点 $1\sim 3$ 满足 $n \le 30$ 。
记 $S_i=\sum_{p_i \mid x \,\land \, x \le m} x$ ,如果我们直接计算 $\sum S_i$ ,会出现重复计算的情况。
不妨记 $T_i = \{x\mid (p_i \mid x) \,\land\,x \le m\}$ ,我们要求的实际上是 $\bigcup_{i=1}^{n} T_i$ 的所有元素的和。
那么这就是一个容斥的事了
可以发现,如果一个数 $x$ 有奇数个 $p_i$ ,那么它对答案的贡献为正,反之为负。
因为 $m$ 的范围使得 $n$ 个质数很难同时出现,所以考虑暴力dfs所有的组合方式和顺序来模拟容斥
当前质数 $p_0$ 的贡献即为 $p_0 \times \frac{r(r+1)}{2}$ ,其中 $r= \left\lfloor\frac{m}{p_0}\right\rfloor$ 。
时间复杂度 $\mathcal{O}(\mathrm{ok})$
代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
const int P = 376544743;
void up(int &x,int y) { x < y ? x = y : 0; }
void down(int &x,int y) { x > y ? x = y : 0; }
void add(int &x,int y) { (x += y) >= P ? x -= P : 0; }
#define N ((int)(105))
int n,m,res,p[N];char c[N];
void dfs(int u, int cnt)
{
int p0 = 1;
for(int i = 1; i <= n; i++) if(c[i]) p0 *= p[i];
if(p0 > m) return;
int r = m / p0, f = (r + 1) * r / 2 % P;
(cnt & 1) ? add(res, p0 * f % P) : add(res, P - p0 * f % P);
for(int i = u; i <= n; i++) if(!c[i]) {
c[i] = 1; dfs(i, cnt + 1); c[i] = 0;
}
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
// freopen("check.in","r",stdin);
// freopen("check.out","w",stdout);
cin >> n >> m;
for(int i = 1; i <= n; i++) cin >> p[i];
sort(p + 1, p + 1 + n); n = unique(p + 1, p + 1 + n) - p - 1;
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= n; j++) c[j] = false;
c[i] = true; dfs(i, 1);
}
cout << res << '\n';
return 0;
}
参考文献: