1 条题解

  • 0
    @ 2025-8-24 23:13:51

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar Tomwsc
    长风破浪会有时,直挂云帆济沧海

    搬运于2025-08-24 23:13:51,当前版本为作者最后更新于2025-04-18 18:33:52,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    P12226 「WyOJ Round 1」启 · 破茧初阳 题解

    思路

    发现数据范围很大,所以我们考虑快速计算答案。如何快速计算答案呢?推式子!

    很明显,这道题目只需要我们简单的推个式子即可。设在 nn 以内能被 aa 整除的数的个数为 xx,能被 lcm(a,b)\operatorname{lcm}(a,b) 整除的数的个数为 yy,能被 cc 整除的数的个数为 zz,能被 lcm(a,c)\operatorname{lcm}(a,c) 整除的数的个数为 pp,能被 lcm(a,b,c)\operatorname{lcm}(a,b,c) 整除的数的个数为 qq,答案为 ansans,则有:

    ans=xy+zp+qans = x-y+z-p+q

    为什么,画个韦恩图然后容斥一下就清楚了……

    如图,阴影部分即为所求。所以令人想到用 aa 的圆圈加上 cc 的圆圈。但因为橙色部分会被多次计算,所以剪掉 aabb 以及 aacc 重合的部分,即 lcm(a,b)\operatorname{lcm}(a,b)lcm(a,c)\operatorname{lcm}(a,c)。此时,不难发现,绿色部分被多减掉了一次,所以还要再加回来,于是便有了加上绿色的部分,即 lcm(a,b,c)\operatorname{lcm}(a,b,c)

    接下来的问题就变成怎样计算最小公倍数了,有这么一个式子:

    lcm(a,b)=a÷gcd(a,b)×b\operatorname{lcm}(a,b)=a\div \gcd(a,b)\times b

    所以只要知道两数的最大公因数即可,辗转相除法可以计算两数的最大公因数,并且时间复杂度是 O(logmin(a,b))O(\log \min(a,b))

    代码

    注意,数据很大,要开 __int128

    #include<bits/stdc++.h>
    #define int __int128
    #define inf (1ll << 62)
    #define regint register int
    #define pb push_back
    #define mp make_pair
    #define PII pair<int , int>
    using namespace std;
    int t , n , a , b , c;
    
    int gcd(int a , int b) {
    	if(!b)
    		return a;
    	return gcd(b , a % b);
    }
    
    inline int lcm(int a , int b) {
    	return a / gcd(a , b) * b;
    }
    
    inline int read() {
    	char c = getchar();
    	int x = 0 , s = 1;
    	while(c < '0' || c > '9') {
    		if(c == '-')
    			s = -1;
    		c = getchar();
    	}
    	while(c >= '0' && c <= '9') {
    		x = x * 10 + c - '0';
    		c = getchar();
    	}
    	return x * s;
    }
    
    void write(int x) {
    	if(x >= 10)
    		write(x / 10);
    	putchar(x % 10 + '0');
    	return;
    }
    
    signed main() {
    	t = read();
    	while(t --) {
    		n = read();
    		a = read();
    		b = read();
    		c = read();
    		write(n / a - n / lcm(a , b) + n / c - n / lcm(a , c) + n / lcm(lcm(a , b) , c));
    		printf("\n");
    	}
    	return 0;
    }
    
    • 1

    信息

    ID
    9960
    时间
    1000ms
    内存
    512MiB
    难度
    3
    标签
    递交数
    0
    已通过
    0
    上传者