zoukankan      html  css  js  c++  java
  • 莫比乌斯反演

    数论的东西总是好难QAQ,像我这样的蒟蒻心态崩溃


    一个好的讲解:莫比乌斯反演


    做了点题,莫比乌斯反演解决的就是快速计算函数的问题。

    你有一个函数F(n)要算,但是特别难算,但是你有另一个函数f(n),F(n)能由f(n)相加求得,而且是倍数关系

    这个时候就可以利用莫比乌斯反演函数简化运算

    还需要强大的数学运算水平QAQ


    上题:

    2301: [HAOI2011]Problem b

    Time Limit: 50 Sec  Memory Limit: 256 MB
    Submit: 6139  Solved: 2803
    [Submit][Status][Discuss]

    Description

    对于给出的n个询问,每次求有多少个数对(x,y),满足a≤x≤b,c≤y≤d,且gcd(x,y) = k,gcd(x,y)函数为x和y的最大公约数。



    Input

    第一行一个整数n,接下来n行每行五个整数,分别表示a、b、c、d、k

    Output

    共n行,每行一个整数表示满足要求的数对(x,y)的个数

    Sample Input

    2

    2 5 1 5 1

    1 5 1 5 2



    Sample Output


    14

    3



    HINT



    100%的数据满足:1≤n≤50000,1≤a≤b≤50000,1≤c≤d≤50000,1≤k≤50000



    了解莫比乌斯反演函数后很快就能看出,一道莫比乌斯反演的入手题

    但是需要简化运算【还不会用编辑器时间紧就不写式子了,上面的链接讲的很清楚】


    要注意的是通常遇到n / d这样的整除运算都是可以分块计算的

    这题中用到的是满足(n / d) = (n / i)的最大的d = n / (n / i)

    还用到了容斥原理


    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<bitset>
    #define LL long long int
    #define REP(i,n) for (int i = 1; i <= (n); i++)
    #define fo(i,x,y) for (int i = (x); i <= (y); i++)
    #define Redge(u) for (int k = head[u]; k != -1; k = edge[k].next)
    using namespace std;
    const int maxn = 50005,maxm = 100005,INF = 1000000000;
    int miu[maxn],prime[maxn],primei = 0,sum[maxn];
    bitset<maxn> isn;
    inline int read(){
    	int out = 0,flag = 1;char c = getchar();
    	while (c < 48 || c > 57) {if (c == '-') flag = -1; c = getchar();}
    	while (c >= 48 && c <= 57) {out = out * 10 + c - 48; c = getchar();}
    	return out * flag;
    }
    void init(){
    	isn.set();
    	miu[1] = 1;
    	for (int i = 2; i < maxn; i++){
    		if (isn[i]) prime[++primei] = i,miu[i] = -1;
    		for (int j = 1; j <= primei && i * prime[j] < maxn; j++){
    			isn[i * prime[j]] = false;
    			if (i % prime[j] == 0){ miu[i * prime[j]] = 0; break; }
    			miu[i * prime[j]] = -miu[i];
    		}
    	}
    	for (int i = 1; i < maxn; i++) sum[i] = sum[i - 1] + miu[i];
    }
    int cal(int n,int m){
    	if (n > m) swap(n,m);
    	int ans = 0,nxt;
    	for (int i = 1; i <= n; i = nxt + 1){
    		nxt = min(n / (n / i),m / (m / i));
    		ans += (sum[nxt] - sum[i - 1]) * (n / i) * (m / i);
    	}
    	return ans;
    }
    int main()
    {
    	init();
    	int N,a,b,c,d,k;
    	N = read();
    	while (N--){
    		a = read(); b = read(); c = read(); d = read(); k = read();
    		a--; c--;
    		a/=k;b/=k;c/=k;d/=k;
    		printf("%d
    ",cal(b,d) - cal(b,c) - cal(a,d) + cal(a,c));
    	}
    	return 0;
    }
    




  • 相关阅读:
    如何用C#在Excel中生成图表?
    SQL2000怎样可以让一个数据库用几个磁盘分区
    用C#快速往Excel写数据
    SQL语句导入导出大全
    js解密
    Word的常用操作
    网页javascript获得当前页面或窗口的各个宽度高度
    用C#动态创建Access数据库
    MSSQL一些精典语句
    寻找Vista下PC硬件驱动
  • 原文地址:https://www.cnblogs.com/Mychael/p/8282824.html
Copyright © 2011-2022 走看看