Educational Codeforces Round 106 (Rated for Div. 2)D. The Number of Pairs

Educational Codeforces Round 106 (Rated for Div. 2)D. The Number of Pairs

题目大意

给你三个正整数 c , d , k \displaystyle c,d,k c,d,k,求满足 c ∗ l c m ( a , b ) + d ∗ g c d ( a , b ) = x \displaystyle c*lcm(a,b)+d*gcd(a,b)=x clcm(a,b)+dgcd(a,b)=x ( a , b ) \displaystyle(a,b) (a,b)对的数量。其中 c , d , k \displaystyle c,d,k c,d,k均小于 1 0 7 \displaystyle10^7 107

简要分析

由于数据量较大,加之又有多组测试样例,这就限定了我们的时间复杂度必须小之又小,大概只能 O ( n ) \displaystyle O(n) O(n)

具体分析

我们首先要对题目的式子进行处理,把它化简,变形到我们可以较为轻松的处理,或是看出它到底要让我们求什么。

首先我们注意到式子中有 l c m ( a , b ) \displaystyle lcm(a,b) lcm(a,b) g c d ( a , b ) \displaystyle gcd(a,b) gcd(a,b),我们知道这两者之间的联系,即 l c m ( a , b ) ∗ g c d ( a , b ) = a ∗ b \displaystyle lcm(a,b)*gcd(a,b)=a*b lcm(a,b)gcd(a,b)=ab,但如果直接把这个式子代进去,似乎也不是非常的美观。
我们不妨设 g c d ( a , b ) = g \displaystyle gcd(a,b) = g gcd(a,b)=g,那么 a = A ∗ g , b = B ∗ g \displaystyle a = A*g,b = B*g a=Ag,b=Bg,其中 g c d ( A , B ) = 1 \displaystyle gcd(A,B) = 1 gcd(A,B)=1,这样便把 a , b \displaystyle a,b a,b与它们的公因数之间的桥梁给直观的搭建了起来,同样利用一开始的式子,我们就可以得到 l c m ( a , b ) = A ∗ B ∗ g \displaystyle lcm(a,b) = A*B*g lcm(a,b)=ABg。这样我们代入题中的式子,便可以得到如下式子:
g ∗ ( A ∗ B ∗ c − d ) = x \displaystyle g*(A*B*c-d) = x g(ABcd)=x
考虑到左边的式子中含有因子 g \displaystyle g g,我们将其移到右侧,考虑到两侧均为整数便可得到 g ∣ x \displaystyle g|x gx
对式子变形,得到:
A ∗ B ∗ c = x g + d \displaystyle A*B*c = \frac{x}{g}+d ABc=gx+d
同样,跟刚才一样,注意到左边含有因子 c \displaystyle c c,说明 c ∣ ( x g + d ) \displaystyle c| (\frac{x}{g}+d) c(gx+d),我们将 c \displaystyle c c移动到左边,得到:
A ∗ B = ( x g + d ) c \displaystyle A*B = \frac{(\frac{x}{g}+d)}{c} AB=c(gx+d)
对于每一个给定的 g \displaystyle g g式子右侧是一个定值,当然是满足条件的值,这样问题就转化为对于每一个给定的,满足条件的 g \displaystyle g g有多少组 ( A , B ) \displaystyle (A,B) (A,B)满足条件,由于 A , B \displaystyle A,B A,B互质,那么对于每一个式子右侧的质因子,左侧一定只有 A 或 B \displaystyle A或B AB有,那么问题就在一次转化,转化为对所有的右侧质因子,逐一分配给 A 或 B \displaystyle A或B AB ,问分配情况总数,这其实就是一个子集问题,设质因子个数为 n \displaystyle n n,则子集数为 2 n \displaystyle 2^n 2n,也就是总的情况数。

具体实现细节

在分析完后,我们可以清楚的知道,我们只需要枚举每一个 x \displaystyle x x的的因子,判断它是否满足式子的条件(即上面分析过程中的几个整除条件),满足,则计算它对答案的贡献。由于数据量之大,意味着我们需要尽可能快的处理每一组数据,这时候我们就需要进行预处理。
分析,我们在处理每组数据时候的复杂度最快是 O ( x ) \displaystyle O(\sqrt{x}) O(x ),所以我们需要 O ( n ) \displaystyle O(n) O(n)的预处理或是接近这个速度的预处理。
对于每一个可能的数,我们需要预处理出它的质因子种类的个数,我们很容易联想到应用筛法,其中常见的两个筛法中较快的是欧拉筛,我们可以通过欧拉筛记录每个数的最小质因子,因为它在筛的过程中就是以每个数的最小质因子来筛的,所以很好联想。
但是我们又要怎么处理质因子个数呢,这其中似乎有着类似递推一样的存在,假设我们已经知道了比一个数小的所有数的质因子个数,又知道了它的最小质因子,那么我们思考,如果这个数除去最小质因子后的数中包含原来的最小质因子,那么它的质因子个数不就与除去后的数相同了吗,反之,如果不包含,个数则加一。

具体代码如下:

//#include<bits/stdc++.h> ----万能头----
#include <iostream>
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<cstring>
#include<cmath>
#include<queue>
#include<list>
#include<map>
#include<unordered_map>
using namespace std;
const int p = 1e9+7;
const int N = 2e7+5;
const int maxn = 1e5+10;
const long long INF = 1e17;
#define REP(i,n) for(int i = 1; i <= n; ++i)
#define REPA(i,j,n) for(int i = j; i <= n; ++i)
#define RREP(i,n) for(int i = n; i >= 1; --i)
#define REPR(i,j,n) for(int i = n; i >= j; --i)
typedef long long ll;
typedef pair<ll,ll> PII;
ll n,m,t;
ll k;
ll mind[N], val[N];
vector<ll> prime;
void get_pr(){
    mind[1] = 1;//下面求质数个数的时候会用到,先不用管
    for(int i = 2; i <= N; ++i){
        if(!mind[i]){
            mind[i] = i;//质数的最小质因子为其本身
            prime.emplace_back(i);//存放质数
        }
        for(auto j : prime){//遍历之前获得每个质数
            if(j*i >= N || j > mind[i])break;//如果越界,或是当前数的质因子小于遍历的质数时跳出
            mind[i*j] = j;//记录最小质因子
        }
    }
    for(int i = 2;i <= N; ++i)//获取每个数的质因数种类的个数
    {
        int j = i/mind[i];//获取除去当前数除以最小质因子之后的数,注意mind的初始化,第一个值!!!
        val[i] = val[j]+(mind[i]!=mind[i/mind[i]]);//如果除去最小质因子后的数最小质因子还是当前数,则数量不变,反之加1
    }


}

void solve() {
    ll c,d,x;
    scanf("%lld%lld%lld",&c,&d,&x);
    ll ans = 0;
    for(int i = 1; i * i<= x; ++i){
        if(x % i != 0)continue;//如果i不是x的因子,则跳过
        int k1 = x/i + d;//i为因子的情况,但注意还有一个对称的因子
        if(k1 % c == 0)ans += 1<<val[k1/c];
        if(i * i == x)continue;//注意,如果当前因子恰好是x的平方根,我们则不能重复计算
        int k2 = i + d;//x去除以i的对称因子,即是i本身
        if(k2 % c == 0)ans += 1<<val[k2/c];
    }

    cout<<ans<<'\n';//这个每组测试的复杂度就成了根号x
}


int main() {
    //ios::sync_with_stdio(0);
    //cin.tie(0);
    //cout.tie(0);

    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);

    get_pr();//init,precalculate
    scanf("%lld",&t);
    while(t--)
        solve();

    fclose(stdin);
    fclose(stdout);

}
"educational codeforces round 103 (rated for div. 2)"是一个Codeforces平台上的教育性比赛,专为2级选手设计评级。以下是有关该比赛的回答。 "educational codeforces round 103 (rated for div. 2)"是一场Codeforces平台上的教育性比赛。Codeforces是一个为程序员提供竞赛和评级的在线平台。这场比赛是专为2级选手设计的,这意味着它适合那些在算法和数据结构方面已经积累了一定经验的选手参与。 与其他Codeforces比赛一样,这场比赛将由多个问题组成,选手需要根据给定的问题描述和测试用例,编写程序来解决这些问题。比赛的时限通常有两到三个小时,选手需要在规定的时间内提交他们的解答。他们的程序将在Codeforces的在线评测系统上运行,并根据程序的正确性和效率进行评分。 该比赛被称为"educational",意味着比赛的目的是教育性的,而不是针对专业的竞争性。这种教育性比赛为选手提供了一个学习和提高他们编程技能的机会。即使选手没有在比赛中获得很高的排名,他们也可以从其他选手的解决方案中学习,并通过参与讨论获得更多的知识。 参加"educational codeforces round 103 (rated for div. 2)"对于2级选手来说是很有意义的。他们可以通过解决难度适中的问题来测试和巩固他们的算法和编程技巧。另外,这种比赛对于提高解决问题能力,锻炼思维和提高团队合作能力也是非常有帮助的。 总的来说,"educational codeforces round 103 (rated for div. 2)"是一场为2级选手设计的教育性比赛,旨在提高他们的编程技能和算法能力。参与这样的比赛可以为选手提供学习和进步的机会,同时也促进了编程社区的交流与合作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值