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;
}