E. Divisor Paths
time limit per test
3 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output
You are given a positive integer DD. Let's build the following graph from it:
For example, here is the graph for D=12D=12:
Edge (4,12)(4,12) has weight 33 because 1212 has divisors [1,2,3,4,6,12][1,2,3,4,6,12] and 44 has divisors [1,2,4][1,2,4]. Thus, there are 33 divisors of 1212 that are not divisors of 44 — [3,6,12][3,6,12].
There is no edge between 33 and 22 because 33 is not divisible by 22. There is no edge between 1212 and 33 because 123=4123=4 is not a prime.
Let the length of the path between some vertices vv and uu in the graph be the total weight of edges on it. For example, path [(1,2),(2,6),(6,12),(12,4),(4,2),(2,6)][(1,2),(2,6),(6,12),(12,4),(4,2),(2,6)] has length 1+2+2+3+1+2=111+2+2+3+1+2=11. The empty path has length 00.
So the shortest path between two vertices vv and uu is the path that has the minimal possible length.
Two paths aa and bb are different if there is either a different number of edges in them or there is a position ii such that aiai and bibi are different edges.
You are given qq queries of the following form:
The answer for each query might be large so print it modulo 998244353998244353.
Input
The first line contains a single integer DD (1≤D≤10151≤D≤1015) — the number the graph is built from.
The second line contains a single integer qq (1≤q≤3⋅1051≤q≤3⋅105) — the number of queries.
Each of the next qq lines contains two integers vv and uu (1≤v,u≤D1≤v,u≤D). It is guaranteed that DD is divisible by both vv and uu (both vv and uu are divisors of DD).
Output
Print qq integers — for each query output the number of the shortest paths between the two given vertices modulo 998244353998244353.
Examples
input
Copy
12 3 4 4 12 1 3 4
output
Copy
1 3 1
input
Copy
1 1 1 1
output
Copy
1
input
Copy
288807105787200 4 46 482955026400 12556830686400 897 414 12556830686400 4443186242880 325
output
Copy
547558588 277147129 457421435 702277623
Note
In the first example:
题意:给你一个数D(<=1e15),D的所有因子(包括1和它本身)作为节点构成无向图,对于某两个因子x,y,若x%y==0且x/y为质数,那么x,y之间就存在一条长为 x的因子数-y的因子数 的边,接下来q(<=3e5)次询问,每次询问a,b,问a到b之间的最短路径都多少条。
思路:看了大佬们的解析,长见识了。
经典的组合数问题:x不断除以它的质因子,直到变成1 的方案数为x的质因子的幂次之和的阶乘 除以 x的每个质因子的幂次的阶乘之积。
分析:显然图中的点很少,若x,y之间有边,显然x%y==0。我们假设询问的两个点x,y,有x%y==0,那么显然最短路就是x除以质因子直到变成y经过的路径(路径长度为因子数之差)。就相当于x除以质因子变成y的方案数,也就是x/y除以它的质因子变成1的方案数。
若x%y!=0,则x到y的路径必然会经过一个数k,其中x%k==0且y%k==0,这个k显然就是x,y的gcd。因此我们直接用map预处理方案数,然后直接map回答,复杂度可以接受。
代码:
#include
#define ll long long
#define inf 0x3f3f3f3f
#define rep(i,a,b) for(register int i=(a);i<=(b);i++)
#define dep(i,a,b) for(register int i=(a);i>=(b);i--)
using namespace std;
const int maxn=3e5+5;
//const double pi=acos(-1.0);
//const double eps=1e-9;
const ll mo=998244353;
ll n,m,k;
int q;
ll ans,tmp,cnt;
int flag;
ll jc[maxn];
ll power(ll a,ll n){
ll sum=1;
while(n){
if(n&1) sum=sum*a%mo;
n>>=1;
a=a*a%mo;
}
return sum;
}
mapmp;
ll cal(ll x){
ll sum1=0,sum2=1;
for(ll i=2;i*i<=x;i++) if(x%i==0){
ll num=0;
while(x%i==0){x/=i;num++;}
sum2=sum2*power(jc[num],mo-2)%mo;
sum1+=num;
}
if(x>1) sum1++;
sum1=jc[sum1]*sum2%mo;
return sum1;
}
int main()
{
jc[0]=1;
rep(i,1,maxn-1) jc[i]=jc[i-1]*i%mo;
int T,cas=1;
//scanf("%d",&T);
//while(T--)
{
scanf("%lld",&n);
for(ll i=1;i*i<=n;i++){
if(n%i==0){
mp[i]=cal(i);
mp[n/i]=cal(n/i);
}
}
scanf("%d",&q);
rep(i,1,q){
ll x,y;
scanf("%lld%lld",&x,&y);
ll k=__gcd(x,y);
ll as=mp[x/k]*mp[y/k]%mo;
printf("%lld\n",as);
}
}
return 0;
}