\le 10^{15} 的数+多组询问分解质因数的小 tip+同余最短路

Codeforces 题面传送门 & 洛谷题面传送门

感谢此题教会我一个东西叫做同余最短路(大雾

首先这个不同 \(k\) 的个数 \(\le 50\) 这个条件显然是让我们对每个 \(k\) 进行一遍预处理并快速求出答案。怎么预处理呢?首先考虑一个非常 trivial 的性质,那就是所有 \(k\) 的非质数因子显然可以表示成质因子的和对吧,所以一个数能够表示成 \(k\) 的若干个质因子的和,当且仅当它能够表示成 \(k\) 的若干个质因子的和。因此考虑先对 \(k\) 进行一遍质因数分解——可以使用 PR 算法,但是我不会,每次 \(\sqrt{k}\) 地分解会超时,这里有一个简单的技巧,之前暑假某场模拟赛出现过,就是显然我们只会用到 \(\le\sqrt{k}\) 的所有质因子,因此可以考虑预处理出 \(\le \sqrt{10^{15}}\) 的所有质数,然后每次分解遍历一遍这个质数集合即可,这样分解的复杂度可以降到 \(\sqrt{10^{15}}·\dfrac{1}{\ln 10^{15}}·50\)

考虑怎样计算答案,如果 \(k\) 本身就是质数那显然只有 \(k\) 的倍数能够表示成 \(k\)\(\ne 1\) 的质因子之和。直接判断一下 \(n\bmod k=0\) 是否成立即可。如果 \(k\) 有两个质因子,那么假设 \(k\) 两个质因子分别为 \(x,y\),那么我们需检验是否 \(\exists a,b\in[0,\infty)\cap\mathbb{Z},s.t.ax+by=n\),显然必须有 \(by\equiv n\pmod{x}\),那么 \(b\) 的最小值 \(b_{\min}=n·y^{-1}\bmod x\),检验一下是否有 \(b_{\min}·y\le n\) 即可。

如果 \(k\) 质因子个数 \(\ge 3\),那么假设 \(k\) 的质因子分别为 \(p_1,p_2,\cdots,p_m\),那么我们需检验是否 \(\exists x_1,x_2,\cdots,x_m\in[0,\infty)\cap\mathbb{Z},s.t.\sum\limits_{i=1}^mp_ix_i=n\),直接检验貌似有点棘手,不过不难发现有一个性质,那就是对于任意 \(x_i\)\(n\),如果 \(n\) 可行,那么 \(n+zp_i\) 也可行,也就是说对于所有 \(j\in[0,p_i)\),必然存在一个界 \(lim_j\),满足所有 \(\bmod x_i=j\) 的数当中,所有 \(\ge lim_j\) 的数都符合要求,所有 \(<lim_j\) 的数都符合要求,考虑怎样求 \(lim_j\),显然 \(lim_0=0\),而对于所有 \(j\in[0,x_i),t\in[1,m]\),显然 \(lim_{(j+p_t)\bmod p_1}\le lim_j+p_t\),这是一个最短路的形式,用 dijkstra 转移即可。并且不难发现对于 \(k\le 10^{15}\),这种情况下 \(k\) 最小的质因子必然 \(\le 10^5\),因此我们对 \(k\) 最小质因子跑同余最短路即可实现 \(10^5\log 10^5·50\) 的复杂度。

话说这场的 D、E,尤其是那个恶心无比的 D……勾起了远古回忆

const int MAXN=1e4;
const int MAXK=1e5;
const int MAXV=3.163e7;
int qpow(int x,int e,int mod){
	int ret=1;
	for(;e;e>>=1,x=1ll*x*x%mod) if(e&1) ret=1ll*ret*x%mod;
	return ret;
}
int qu,pr[MAXV/8+5],prcnt,vis[MAXV+5];
void sieve(int n){
	for(int i=2;i<=n;i++){
		if(!vis[i]) pr[++prcnt]=i;
		for(int j=1;j<=prcnt&&pr[j]*i<=n;j++){
			vis[pr[j]*i]=1;if(i%pr[j]==0) break;
		}
	}
}
int res[MAXN+5];
map<ll,vector<pair<ll,int> > > mpv;
vector<ll> decomp(ll v){
	vector<ll> ret;
	for(int i=1;i<=prcnt;i++) if(v%pr[i]==0){
		ret.pb(pr[i]);
		while(v%pr[i]==0) v/=pr[i];
	} if(v>1) ret.pb(v);
	return ret;
}
ll dis[MAXK+5];
int main(){
	sieve(MAXV);scanf("%d",&qu);
	for(int i=1;i<=qu;i++){
		ll n,k;scanf("%lld%lld",&n,&k);
		if(k!=1) mpv[k].pb(mp(n,i));
	}
	for(auto it:mpv){
		ll v=it.fi;vector<pair<ll,int> > qv=it.se;
		vector<ll> pr=decomp(v);
		if(pr.size()==1){
			for(pair<ll,int> p:qv) res[p.se]=(p.fi%pr[0]==0);
		} else if(pr.size()==2){
			ll x=pr[0],y=pr[1],ivy=qpow(y%x,x-2,x);
			for(pair<ll,int> p:qv){
				int bmin=1ll*(p.fi%x)*ivy%x;
				res[p.se]=(p.fi>=1ll*bmin*y);
			}
		} else {
			int x=pr[0];memset(dis,63,sizeof(dis));dis[0]=0;
			priority_queue<pair<ll,int>,vector<pair<ll,int> >,greater<pair<ll,int> > > q;
			q.push(mp(0,0));
			while(!q.empty()){
				pair<ll,int> p=q.top();q.pop();
				int cur=p.se;
				for(int i=1;i<pr.size();i++){
					if(dis[(cur+pr[i])%x]>dis[cur]+pr[i]){
						dis[(cur+pr[i])%x]=dis[cur]+pr[i];
						q.push(mp(dis[(cur+pr[i])%x],(cur+pr[i])%x));
					}
				}
			}
			for(pair<ll,int> p:qv) res[p.se]=(p.fi>=dis[p.fi%x]);
		}
	}
	for(int i=1;i<=qu;i++) printf("%s\n",(res[i])?"YES":"NO");
	return 0;
}