题解 CF986F【Oppa Funcan Style Remastered】

$\text{Link}$

惊讶,看了看最优解发现我 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~

posted @ 2021-12-11 08:53  ffffyc  阅读(27)  评论(0)    收藏  举报  来源