Educational Codeforces Round 85 (Rated for Div. 2)E. Divisor Paths(数论,思维)

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:

  • each vertex is a divisor of DD (not necessarily prime, 11 and DD itself are also included);
  • two vertices xx and yy (x>yx>y) have an undirected edge between them if xx is divisible by yy and xyxy is a prime;
  • the weight of an edge is the number of divisors of xx that are not divisors of yy.

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:

  • vv uu — calculate the number of the shortest paths between vertices vv and uu.

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:

  • The first query is only the empty path — length 00;
  • The second query are paths [(12,4),(4,2),(2,1)][(12,4),(4,2),(2,1)] (length 3+1+1=53+1+1=5), [(12,6),(6,2),(2,1)][(12,6),(6,2),(2,1)] (length 2+2+1=52+2+1=5) and [(12,6),(6,3),(3,1)][(12,6),(6,3),(3,1)] (length 2+2+1=52+2+1=5).
  • The third query is only the path [(3,1),(1,2),(2,4)][(3,1),(1,2),(2,4)] (length 1+1+1=31+1+1=3).

题意:给你一个数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<bits/stdc++.h>
#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;
}
map<ll,ll>mp;
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;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值