题目大意
有 N N 个舞台,每个舞台有一个,每秒钟i舞台上的人会走向舞台 fi f i ,给出 T T 组询问,现在时间为秒钟, N N 个舞台,问你能不能构造出每个使得每个舞台上的人经过K秒钟,能回到自己原本的舞台上。
N<=1018,K<=1015,T<=104 N <= 10 18 , K <= 10 15 , T <= 10 4 不同的 K K 最多只有个
Analysis
若构造出一个环,使得 i i 舞台的人经过秒后回到自己舞台上,那么该环经过的点都可以回到自己舞台上。而对于询问只用回答 YES Y E S 和 NO N O ,环就可以任意构造。那么也就是拿 K K 的因子来填满长度为的序列,考虑将 K K 分解质因数,那么也就是要求
代码
# include<cstdio>
# include<cstring>
# include<algorithm>
# include<cmath>
# include<queue>
# include<ctime>
using namespace std;
typedef long long ll;
const int N = 2e4 + 5;
const int M = 1e6 + 5;
struct node
{
ll n,k;
int pos;
}q[N];
struct data
{
int id; ll d;
bool operator < (data r) const
{ return d > r.d; }
};
priority_queue <data> g;
ll dis[M];
int ans[N],vis[M],p[M];
int tot,cnt;
bool cmp(node a,node b) { return a.k < b.k; }
ll abs1(ll x) { return x < 0 ? -x : x; }
ll gcd(ll x,ll y) { return !y ? x : gcd(y,x % y); }
inline ll mul(ll x,ll p,ll mo)
{
ll ret = 0;
for (; p ; p >>= 1,x = (x + x) % mo)
if (p & 1) ret = (ret + x) % mo;
return ret;
}
inline ll pow(ll x,ll p,ll mo)
{
ll ret = 1;
for (; p ; p >>= 1,x = mul(x,x,mo))
if (p & 1) ret = mul(ret,x,mo);
return ret;
}
inline bool Mill(ll x)
{
if (x < 2) return 0;
int s = 0; ll z = x; --x;
while (!(x & 1)) x >>= 1,++s;
for (int i = 0 ; i < 10 ; ++i)
{
ll k = (rand() * rand()) % z;
while (!k) k = (rand() * rand()) % z;
k = pow(k,x,z);
ll pre = k;
for (int j = 0 ; j < s ; ++j)
{
k = mul(k,k,z);
if (k == 1 && pre != 1 && pre != z - 1) return 0;
pre = k;
}
if (k != 1) return 0;
}
return 1;
}
inline ll rho(ll x)
{
int l = 1,r = 2;
ll x0 = (rand() * rand()) % x,y = x0,c = (rand() * rand()) % x + 1;
while (1)
{
++l;
x0 = (mul(x0,x0,x) + c) % x;
ll now = gcd(abs1(x0 - y),x);
if (now != 1 && now != x) return now;
if (x0 == y) return x;
if (l == r) r <<= 1,y = x0;
}
}
inline void divi(ll x)
{
if (x == 1) return;
if (Mill(x)) { p[++cnt] = x; return; }
ll d = rho(x);
divi(x / d); divi(d);
}
inline void dij()
{
dis[0] = 0,g.push((data){0,0});
while (!g.empty())
{
data x = g.top(); g.pop();
if (vis[x.id]) continue;
vis[x.id] = 1;
for (int i = 2 ; i <= cnt ; ++i)
{
int v = (x.id + p[i]) % p[1];
if (dis[v] > dis[x.id] + p[i])
{
dis[v] = dis[x.id] + p[i];
g.push((data){v,dis[v]});
}
}
}
}
int main()
{
int t; scanf("%d",&t);
for (int i = 1 ; i <= t ; ++i) scanf("%I64d%I64d",&q[i].n,&q[i].k),q[i].pos = i;
sort(q + 1,q + t + 1,cmp);
for (int i = 1 ; i <= t ; ++i)
{
if (q[i].k == q[i - 1].k)
{
if (!cnt) { ans[q[i].pos] = 0; continue; }
if (cnt == 1)
{
if (q[i].n % q[i].k == 0) ans[q[i].pos] = 1;
else ans[q[i].pos] = 0;
continue;
}
if (cnt == 2)
{
ll b = q[i].n % p[1] * pow((ll)p[2],p[1] - 2,(ll)p[1]) % p[1];
if (b * p[2] <= q[i].n) ans[q[i].pos] = 1;
else ans[q[i].pos] = 0;
continue;
}
ans[q[i].pos] = dis[q[i].n % (ll)p[1]] <= q[i].n;
continue;
}
cnt = 0;
divi(q[i].k);
sort(p + 1,p + cnt + 1); cnt = unique(p + 1,p + cnt + 1) - p - 1;
if (!cnt) { ans[q[i].pos] = 0; continue; }
if (cnt == 1)
{
if (q[i].n % q[i].k == 0) ans[q[i].pos] = 1;
else ans[q[i].pos] = 0;
continue;
}
if (cnt == 2)
{
ll b = q[i].n % p[1] * pow((ll)p[2],p[1] - 2,(ll)p[1]) % p[1];
if (b * p[2] <= q[i].n) ans[q[i].pos] = 1;
else ans[q[i].pos] = 0;
continue;
}
for (int j = 0 ; j < p[1] ; ++j) vis[j] = 0,dis[j] = 1e18;
dij();
ans[q[i].pos] = dis[q[i].n % p[1]] <= q[i].n;
}
for (int i = 1 ; i <= t ; ++i)
if (ans[i]) puts("YES");
else puts("NO");
return 0;
}