D. The Number of Pairs(思维+数论+欧拉筛/埃筛)

https://codeforces.com/contest/1499/problem/D


参考题解:

https://blog.csdn.net/ghu99999/article/details/115006433


思路:

首先由裴蜀定理ax+by=c有解的充分必要条件可以得到 

对于方程 lcm(a,b)*c+gcd(a,b)*(-d)=x , x必定是gcd(gcd(a,b),lcm(a,b))的倍数

把gcd(a,b)看成a,b的质因取min,lcm(a,b)看成a,b的质因数取max,可以发现答案仍是gcd(a,b)

因此可以知道,gcd(a,b)是x的约数,此时sqrt可以枚举出gcd(a,b)的取值,由于c,d,已知,O1就可以得出lcm(a,b);

此时问题就变成了已经知道gcd(a,b),lcm(a,b)求满足的ab对有多少个。

这里就是结论的部分也是比较思维的部分。

参考:https://blog.csdn.net/qq_36394234/article/details/114994557

 


至此,可以2^nO1去算答案了,不过要注意,还要满足式子的整除性。也就是lcm%c==0,并且lcm得是gcd的倍数。

于是开始预处理部分。常规来说,我们欧拉筛搞完log跑,n+nlogn。然而我都开了LL,导致tle1迷惑半天。最后1996ms卡过去。

#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<cstdio>
#include<algorithm>
#define debug(a) cout<<#a<<"="<<a<<endl;
#define LL int
using namespace std;
const int maxn=2e7+5000;
inline LL read(){LL x=0,f=1;char ch=getchar();	while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
return x*f;}
LL primes[1270610],m=0;
LL v[maxn];//[]存每个数的最小质因子
LL num[maxn];
void getprimes(LL n){
	for(int i=2;i<=n;i++){
		if(v[i]==0) {v[i]=i;primes[++m]=i;}
		for(LL j=1;j<=m;j++){
			if(primes[j]>v[i]||primes[j]>n/i)	break;
			v[i*primes[j]]=primes[j];
		}
	}
    for(int i=2;i<=n;i++){
        LL k=i;LL cnt=0;
        while(k>1){
            LL temp=v[k];
            cnt++;
            while(k%temp==0){
                k/=temp;
            }
        }
        if(k>1) cnt++;
        num[i]=cnt;
    }
}
LL add(LL c,LL d,LL x,LL gcd){
    long long int lcm=x+1ll*d*gcd;
    long long int res=0;
    if(lcm%c==0){
        lcm/=c;
        if(lcm%gcd==0){
            res+=(1ll<<num[lcm/gcd]);
        }
    }
    return res;
}
void solve(LL c,LL d,LL x){
   long long int ans=0;
    for(LL i=1;i*i<=x;i++){
        if(x%i==0){
            ans+=add(c,d,x,i);
            if(i*i!=x) ans+=add(c,d,x,x/i);
        }
    }
    printf("%lld\n",ans);
}
int main(void)
{
  getprimes(20000010);
  int T;scanf("%d",&T);
  while(T--){
    LL c,d,x;c=read();d=read();x=read();
    solve(c,d,x);
  }
return 0;
}

这也太危险了把。看了看别人都是埃筛,难道欧拉不行了嘛?还是能On筛出来的

我们再来看看欧拉筛,num[i]记为i的质因数种类个数。当i%primes[j]!=0的时候,其num[i*primes[j]]的更新来自num[i]的一部分和primes[j]这个质数。

当i%primes[j[==0的时候,primes[j]其本身包含在num[i]中了。因此num[i*primes[j]=num[i]

然后On跑。1200ms。

还是没有埃筛快阿。埃筛开cin还是1005ms呢..

#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<cstdio>
#include<algorithm>
#define debug(a) cout<<#a<<"="<<a<<endl;
#define LL int
using namespace std;
const int maxn=2e7+5000;
inline LL read(){LL x=0,f=1;char ch=getchar();	while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
return x*f;}
LL primes[1270610],m=0;
LL v[maxn];//[]存每个数的最小质因子
LL num[maxn];
void getprimes(LL n){
	for(int i=2;i<=n;i++){
		if(v[i]==0) {v[i]=i;primes[++m]=i;num[i]=1;}
		for(LL j=1;j<=m&&primes[j]<=n/i;j++){

			v[i*primes[j]]=primes[j];
			if(i%primes[j]==0){
                num[i*primes[j]]=num[i];
                break;
			}
			num[i*primes[j]]=(1+num[i]);
		}
	}
}
LL add(LL c,LL d,LL x,LL gcd){
    long long int lcm=x+1ll*d*gcd;
    long long int res=0;
    if(lcm%c==0){
        lcm/=c;
        if(lcm%gcd==0){
            res+=(1ll<<num[lcm/gcd]);
        }
    }
    return res;
}
void solve(LL c,LL d,LL x){
   long long int ans=0;
    for(LL i=1;i*i<=x;i++){
        if(x%i==0){
            ans+=add(c,d,x,i);
            if(i*i!=x) ans+=add(c,d,x,x/i);
        }
    }
    printf("%lld\n",ans);
}
int main(void)
{
  getprimes(20000010);
  int T;scanf("%d",&T);
  while(T--){
    LL c,d,x;c=read();d=read();x=read();
    solve(c,d,x);
  }
return 0;
}

猜你喜欢

转载自blog.csdn.net/zstuyyyyccccbbbb/article/details/115016843