Educational Codeforces Round 85 (Rated for Div. 2) E. Divisor Paths(思维+可重集排列数)

题目链接

题意:给你一个整数D,有一个无向图,图的节点为 D 的因子,若 x % y == 0 && x / y 是一个质数,则节点 x 和 y 有一条无向边,边权为 是 x 的因子但不是 y 的因子的数的个数。有 q 次询问,每次询问输入两个节点 x、y 问节点 x 到节点 y 边权最小的路径有多少条,输出答案对 998244353 取模后的结果

1 <= D <= 10^15; 1 <= q <= 3*10^5 ;  1 <= x,y <= D

做法:参考自来:博客1、博客2

①:由博客2可知

至于为什么 边权  是x的因子不是y的因子 == num(x)-num(y)? 因为x、y都是D的因子,并且x 与y互质的原因吧

②:由博客1可知:

Educational Codeforces Round 85 (Rated for Div. 2) E. Divisor Paths(思维+可重集排列数)_第1张图片

③:怎么计算u  到  v 路径上 某质因数的个数 ?(假设u和v不互质)

肯定跟gcd有关,假设有个素数P1 :

u->gcd->c   u中有:P1^(a1)  v中有: P1^(a2)  gcd中有: P1^(a3)   a3

u  到  v 路径上 某质因数的个数=max(a2-a3,a1-a3) 因为a3  等于a1 或者 a2 其中一个

所以代码中就出现是求 |a1-a2|

#include
#define rep(i,a,b) for(int i=a;i<=(b);++i)
#define per(i,a,b) for(int i=a;i>=(b);--i)
#define mem(a,x) memset(a,x,sizeof(a))
#define pb push_back
#define pi pair
#define mk make_pair
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
const int N=1e3+10,M=1e6+5;
const ll mod=998244353;
ll inv[N],fac[N],pre[N],len;

void init()
{
    fac[0]=1;inv[0]=inv[1]=1;

    for(int i=2;i>d>>_;
	for(ll i=2;i*i<=d;++i){
        if(d%i==0){
            ll cnt=0;
            while(d%i==0) d=d/i,cnt++;
            pre[++len]=i;
        }
	}
	if(d!=1) pre[++len]=d;

	while(_--)
    {
        ll u,v;
        scanf("%lld%lld",&u,&v);
        ll fz1=0,fz2=0,ans=1;
        for(int i=1;i<=len;++i){
            ll num=0;
            while(u%pre[i]==0) u/=pre[i],num++;
            while(v%pre[i]==0) v/=pre[i],num--;

            if(num>0){
                fz1+=num;
                ans=ans*inv[num]%mod;
            }
            else{
                fz2+=(-num);
                ans=ans*inv[-num]%mod;
            }
        }
        ans=ans*fac[fz1]%mod*fac[fz2]%mod;
        printf("%lld\n",ans);
    }
}

 

你可能感兴趣的:(codeforce题解,数学--可重集排列)