• P3455 [POI2007]ZAP-Queries


    题意翻译

    题目描述

    密码学家正在尝试破解一种叫 BSA 的密码。

    他发现,在破解一条消息的同时,他还需要回答这样一种问题:

    给出 a,b,d,求满足 1≤x≤a1,1≤y≤b1,且 gcd⁡(x,y)=d 的二元组 (x,y) 的数量。

    因为要解决的问题实在太多了,他便过来寻求你的帮助。

    输入格式

    输入第一行一个整数 n,代表要回答的问题个数。

    接下来 n 行,每行三个整数 a,b,d

    输出格式

    对于每组询问,输出一个整数代表答案。

    数据范围

    1≤n≤500001 1≤d≤a,b≤50000

    输入输出样例

    输入 #1

    2
    4 5 2
    6 4 3
    

    输出 #1

    3
    2
    

    一句话题意 求(displaystyle sum_{i=1}^nsum_{j=1}^m[gcd(i , j) = d])

    其中 d 给定

    化简一下式子

    (large displaystyle sum_{i=1}^nsum_{j=1}^m[gcd(i,j)=d])

    =(large displaystyle sum_{i=1}^{leftlfloorfrac{a}{d} ight floor}sum_{j=1}^{leftlfloorfrac{b}{d} ight floor}[gcd(i,j) = 1])

    =(displaystyle sum_{i=1}^{leftlfloorfrac{a}{d} ight floor}sum_{j=1}^{leftlfloorfrac{b}{d} ight floor}sum_{p | i , j}mu(p))

    =(displaystyle sum_{p=1}^{leftlfloorfrac{a}{d} ight floor} mu(p)sum_{i=1}^{leftlfloorfrac{a}{dp} ight floor}sum_{j=1}^{leftlfloorfrac{b}{dp} ight floor} 1)

    到这基本就完了 , 对a , b 一起整除分块 , 在对mu[p] 求个前缀和。就没了

    #include<iostream>
    #include<cstdio>
    using namespace std;
    const int N = 5e4+100;
    #define int long long
    int tot;
    int vis[N] , prime[N] , mu[N];
    long long sum[N];
    void Init()
    {
    	int maxn = 5e4;
    	mu[1] = 1; sum[1] = 1;
    	for(int i = 2 ; i <= maxn ; ++i)
    	{
    		if(!vis[i]) { prime[++tot] = i; mu[i] = -1; }
    		for(int j = 1 ; j <= tot && i * prime[j] <= maxn ; ++j)
    		{
    			vis[i * prime[j]] = 1;
    			if(i % prime[j]) mu[i*prime[j]] = -mu[i];
    			else { mu[i*prime[j]] = 0; break; }
    		
    		}
    		sum[i] = sum[i-1] + mu[i];
    	}
    	return ;
    }
    
    signed main()
    {
    	Init();
    	int n , a , b , d; scanf("%lld" ,&n);
    	while(n --)
    	{
    		scanf("%lld%lld%lld",&a,&b,&d); a /= d; b /= d;
    		if(a > b) swap(a , b);
    		long long ans = 0;
    		for(int p = 1 , r ; p <= a ; p = r + 1)
    		{
    			r = min(a , min(a / (a / p) , b / (b / p)));
    			ans = ans + (sum[r] - sum[p-1]) * (a / p) * (b / p); // a / p & b / p 是整除 
    		}
    		printf("%lld
    " , ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    IO模式 select、poll、epoll
    C++设计模式——SingleTon单件模式
    C和C++区别——前置自增与后置自增
    进程——父子进程共享
    一个例子理解c++函数模板的编译
    C/C++多参数函数参数的计算顺序与压栈顺序
    经常登录Linux,用户密码背后的知识了解一下
    一道值得思考的fork()面试题
    vim实用快捷键整理
    Linux硬链接与软连接
  • 原文地址:https://www.cnblogs.com/R-Q-R-Q/p/12164670.html
Copyright © 2020-2023  润新知