给定两个数b,d,问[1,b]和[1,d]区间上有多少对互质的数。(x,y)和(y,x)算一个。
对于[1,b]部分,用欧拉函数直接求。对于大于b的部分,求n在[1,b]上有多少个互质的数,用容斥原理。 主要学习容斥原理的写法,本题使用DFS。容斥原理复杂度比较高,是指数复杂度。 输出长整型不能用lld,必须用I64d。#include#include #include #include #include using namespace std;typedef long long ll;const int maxn = 1e5 + 7;int a, b, c, d, k;bool isPrime[maxn];ll euler[maxn];ll sumeuler[maxn];int p[maxn][20], ps[maxn];void initPrimes(){ memset(isPrime, 1, sizeof(isPrime)); for (int i = 1; i < maxn; i++){ euler[i] = i; } for (int i = 2; i < maxn; i++){ if (isPrime[i]){ for (int j = i; j < maxn; j += i){ isPrime[j] = false; p[j][ps[j]++] = i; euler[j] = euler[j] * (i - 1) / i; } } } sumeuler[1] = 1; for (int i = 2; i < maxn; i++){ sumeuler[i] = sumeuler[i - 1] + euler[i]; }}ll dfs(int ind, int n, int x){//容斥原理核心代码 ll s = 0; for (int i = ind; i < ps[x]; i++){ s += n / p[x][i] - dfs(i + 1, n / p[x][i], x); } return s;}ll huzhi(int n, int x){//0~n之间,与x互质的数字个数 return n - dfs(0, n, x);}int main(){ freopen("in.txt", "r", stdin); initPrimes(); int caseCount; scanf("%d", &caseCount); for (int caseid = 1; caseid <= caseCount; caseid++){ scanf("%d%d%d%d%d", &a, &b, &c, &d, &k); ll ans; if (k == 0) ans = 0; else{ if (b > d)swap(b, d); b /= k, d /= k; ans = sumeuler[b]; for (int i = b + 1; i <= d; i++){ ans += huzhi(b, i); } } printf("Case %d: %I64d\n", caseid, ans); } return 0;}
容斥原理的另一种写法:
int calc(int n,int m)//n < m,求1-n内和m互质的数的个数{ getFactors(m); int ans = 0; for(int i = 1;i < (1<< fatCnt;j++) if(i&(1<
容斥原理项的个数为2的幂次,肯定不会太大,所以一定可以用一个int来表示所有情况。
本题还可以用莫比乌斯反演来解决。
#include#include #include #include #include #include #include #include