题解 CF986F【Oppa Funcan Style Remastered】
惊讶,看了看最优解发现我 300+ms,别人 6s+?
另外这题 *3300?
题意
给你 $n$ 和 $k$,问 $n$ 能否表示为 $k$ 的若干非 $1$ 因子之和,每个因子可用无限次。
$t$ 组数据,令 $t_k$ 表示所有数据中不同 $k$ 的数量。
$n\le 10^{18},k\le 10^{15},t\le 10^4,t_k\le 50$。
题解
引理:若 $n$ 能表示为 $k$ 的若干非 $1$ 因子之和,则 $n$ 能表示为 $k$ 的若干质因子之和。
证:设 $n=\displaystyle\sum_{i=1}^d w_i$,若 $w_i\notin\Bbb P$,则必然可以找到一个质数 $p|w_i$,显然,$p$ 是 $k$ 的质因子,$w_i$ 便可用 $\dfrac {w_i}p$ 个 $p$ 代替。
首先对每个 $k$ 分别计算,设 $\displaystyle k=\prod_{i=1}^dp_i^{q_i}$,其中 $p_i\le p_{i+1}$。
对 $d$ 分类讨论:
- $d=0$:很显然,$k=1$,由于要的是质因子,所以无解。
- $d=1$:很显然,$k\in\Bbb P$,由于只有 $k$ 一个质因子即它自己,直接判断 $[k|n]$ 即可。
- $d=2$:设 $k=x^{u}y^{v}$,很显然,指数在这里没用。假设有解,令 $ax+by=n$,则易得 $by\equiv n(\bmod x)$,求解逆元 $y^{-1}$,带回计算 $[y\times(n\times y^{-1}\bmod x)\le n]$ 即可。
- $d\ge 3$:看起来并不好直接求。
我们可以发现,对于 $d\ge 3$,$p_1\le\sqrt[3]{k}\le 10^5$。此时我们需要做的是,给定初始状态 $0$ 和 $d$ 种转移,第 $i$ 种转移的权值是 $p_i$,给出一堆询问,求能否通过初始状态转移到 $n$。
此时需要引入一个算法:同余最短路。
考虑令 $s_i$ 表示以 $0$ 为初始状态,能转移到的 $u\bmod p_1=i$ 的最小的 $u$。于是对于一个询问 $n$,只需考虑 $[s_{n\bmod p_1}\le n]$ 即可。(显然,之后可以一直 $+p_1$ 拼出 $n$)
那么怎么计算 $s$ 呢?
考虑图论建模,转移可以看作对于所有 $2\le i\le d,0\le j<p_1$,连边 $j\to(j+p_i)\bmod p_1$,权值为 $p_i$,从 $0$ 开始使用最短路算法即可得到答案。
可以发现,$d\le13$,边数是 $\Theta(d\sqrt[3]k)$ 的,点数是 $\Theta(\sqrt[3]k)$ 的,所以该算法的时间复杂度是对的。
另外,$k$ 很大,分解质因数要用 Pollard-Rho。
于是这道题就做完了,时间复杂度是 $\Theta(t\log k+t_kd\sqrt[3]k\log k)$,显然跑不满,可以通过。
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
namespace IO{//by cyffff
}
const int N=1e5+10;
namespace PR{
#define lll __int128
inline ll qpow(ll x,ll y,const ll mod){
ll res=1;
while(y){
if(y&1) res=(lll)res*x%mod;
x=(lll)x*x%mod;
y>>=1;
}
return res;
}
inline bool Miller_Rabin(ll x,int a){
ll y=x-1;
while(y){
ll res=qpow(a,y,x);
if(res!=1&&res!=x-1) return 0;
if(y&1||res==x-1) return 1;
y>>=1;
}
return 1;
}
inline bool Isprime(ll x){
if(x<2||x==46856248255981) return 0;
if(x==2||x==3||x==7||x==61||x==24251) return 1;
if(x%6!=1&&x%6!=5) return 0;
return Miller_Rabin(x,2)&&Miller_Rabin(x,61);
}
inline ll f(ll x,ll c,ll n){
return ((lll)x*x+c)%n;
}
inline ll Pollard_Rho(ll x){
ll s=0,t=0,c=1ll*rand()%(x-1)+1,val=1;
int stp,g=1;
for(;;g<<=1,s=t,val=1){
for(stp=1;stp<=g;stp++){
t=f(t,c,x);
val=(lll)val*abs(t-s)%x;
if(!(stp&127)){
ll q=__gcd(val,x);
if(q>1) return q;
}
}
ll q=__gcd(val,x);
if(q>1) return q;
}
}
inline void solve(ll x,ll cnt,vector<ll> &ans){
if(x<2) return ;
if(Isprime(x)) {for(int i=1;i<=cnt;i++)ans.push_back(x);return ;}
ll pri=x;
for(;pri>=x;pri=Pollard_Rho(x));
ll s=0;
for(;x%pri==0;x/=pri)s++;
solve(x,cnt,ans),solve(pri,cnt*s,ans);
}
inline void decompose(ll x,vector<ll>&ans){
solve(x,1,ans);
}
}
map<ll,int>mp;
struct nd{
ll n;
int id;
};
struct node{
ll k;
vector<nd>vec;
}tmp[70];
int cnt,T;
bool ans[N];
inline int qpow(ll x,ll y,ll p){
ll res=1;
x%=p;
while(y){
if(y&1) res=res*x%p;
x=x*x%p;
y>>=1;
}
return res;
}
int cntt,head[N];
ll dis[N];
bool vis[N];
struct Edge{
int to,nxt;
ll w;
}a[N*30];
inline void add(int u,int v,ll w){
cntt++;
a[cntt].to=v;
a[cntt].nxt=head[u];
a[cntt].w=w;
head[u]=cntt;
}
struct nodeE{
int x;
ll d;
inline friend bool operator<(const nodeE &a,const nodeE &b){
return a.d>b.d;
}
};
priority_queue<nodeE>q;
inline void Dijkstra(int s){
memset(vis,0,sizeof(vis));
memset(dis,127,sizeof(dis));
dis[s]=s;
q.push({s,dis[s]});
while(!q.empty()){
nodeE p=q.top();
q.pop();
int rt=p.x;
if(vis[rt]) continue;
vis[rt]=1;
for(int i=head[rt];i;i=a[i].nxt){
int t=a[i].to;
if(dis[t]>dis[rt]+a[i].w){
dis[t]=dis[rt]+a[i].w;
if(!vis[t])
q.push({t,dis[t]});
}
}
}
}
/*
4
41 236447
7 1533
128 68191
1188 267623
*/
inline void solve(node p){
ll k=p.k;
vector<ll>d;
PR::decompose(k,d);
sort(d.begin(),d.end());
d.resize(unique(d.begin(),d.end())-d.begin());
int sz=d.size();
if(sz==0){
return ;
}else if(sz==1){
for(auto tmp:p.vec)
ans[tmp.id]=tmp.n%k==0;
}else if(sz==2){
ll x=d[0],y=d[1];
for(auto tmp:p.vec){
ll n=tmp.n;
if(n%x==0) ans[tmp.id]=1;
else{
ll pp=n%x*qpow(y,x-2,x)%x;
ans[tmp.id]=(lll)pp*y<=n;
}
}
}else{
cntt=0;
memset(head,0,sizeof(head));
for(int i=0;i<d[0];i++)
for(int j=1;j<sz;j++)
add(i,(i+d[j])%d[0],d[j]);
Dijkstra(0);
for(auto tmp:p.vec){
ll n=tmp.n;
ans[tmp.id]=dis[n%d[0]]<=n;
}
}
}
int main(){
T=read();
for(int i=1;i<=T;i++){
ll n=read(),k=read();
if(!mp[k]) mp[k]=++cnt;
int t=mp[k];
tmp[t].k=k;
tmp[t].vec.push_back({n,i});
}
for(int i=1;i<=cnt;i++)
solve(tmp[i]);
for(int i=1;i<=T;i++)
puts(ans[i]?"YES":"NO");
flush();
}
再见 qwq~

浙公网安备 33010602011771号