CF986F Oppa Funcan Style Remastered
CF986F
给定 与 ,问是否能将 分为若干个 的非 因数之和,每个因数都可以被选多次。
一共 组询问。
对于每组询问,若满足输出 Yes
,否则输出 No
。
对于 的数据,保证 且最多有 种不同的 。
sol
首先发现,若 能被表示成若干个 的非 因数之和,则 也一定能被表示成若干个 的质因子之和。
证明:每个 的非质因子一定能被表示成 的形式,其中 为质数,则将该非质因子拆成 个 相加即可。
然后考虑将 质因子分解,设 ,其中 为质数, 为自然数。
由于不同的 最多只有 个,所以可以考虑筛完质数后枚举分解,由于 的质数只有约 个,所以这部分总时间复杂度大约在 级别,可过。(当然也可以用 Pollard-Rho
分解)
再对 分类讨论:
- :显然,,无解。
- :显然,,直接判断 即可。
- :设 ,那么题意转换为判断是否 ,假设有解,显然有 的最小值 ,最后判断 即可。
- :根据上面的思路,题意转换为判断是否 ,直接检验貌似有点棘手,不过不难发现有一个性质,那就是对于任意 如果 可行,那么 也可行,发现这类似于同余。
于是引入一个算法:同余最短路。
考虑令 表示能被表示出来的满足 的最小的 。
于是对于一个询问 ,只需判断 即可。
那么怎么计算 呢?
转到图上,对于所有 ,连边 ,权值为 ,从 开始使用最短路算法即可得到 。
可以发现,,边数是 的,点数是 的,可过。
总时间复杂度为 ,可过。
最优解
#include <bits/stdc++.h>
using namespace std;
namespace PR
{
typedef long long ll;
#define lll __int128
template <class kkk>
inline kkk qr(kkk sample)
{
kkk ret = 0, sgn = 1;
char cur = getchar();
while (!isdigit(cur))
sgn = (cur == '-' ? -1 : 1), cur = getchar();
while (isdigit(cur))
ret = (ret << 1) + (ret << 3) + cur - '0', cur = getchar();
return sgn == -1 ? -ret : ret;
}
ll max_factor;
inline ll gcd(ll a, ll b)
{
if (b == 0)
return a;
return gcd(b, a % b);
}
inline ll qp(ll x, ll p, ll mod)
{
ll ans = 1;
while (p)
{
if (p & 1)
ans = (lll)ans * x % mod;
x = (lll)x * x % mod;
p >>= 1;
}
return ans;
}
inline bool mr(ll x, ll b)
{
ll k = x - 1;
while (k)
{
ll cur = qp(b, k, x);
if (cur != 1 && cur != x - 1)
return false;
if ((k & 1) == 1 || cur == x - 1)
return true;
k >>= 1;
}
return true;
}
inline bool prime(ll x)
{
if (x == 46856248255981ll || x < 2)
return false;
if (x == 2 || x == 3 || x == 7 || x == 61 || x == 24251)
return true;
return mr(x, 2) && mr(x, 61);
}
inline ll f(ll x, ll c, ll n)
{
return ((lll)x * x + c) % n;
}
inline ll PR(ll x)
{
ll s = 0, t = 0, c = 1ll * rand() % (x - 1) + 1;
int stp = 0, goal = 1;
ll val = 1;
for (goal = 1;; goal <<= 1, s = t, val = 1)
{
for (stp = 1; stp <= goal; ++stp)
{
t = f(t, c, x);
val = (lll)val * abs(t - s) % x;
if ((stp % 127) == 0)
{
ll d = gcd(val, x);
if (d > 1)
return d;
}
}
ll d = gcd(val, x);
if (d > 1)
return d;
}
}
inline void fac(ll x, set<ll> &st)
{
if (x <= max_factor || x < 2)
return;
if (prime(x))
{
st.insert(x);
return;
}
ll p = x;
while (p >= x)
p = PR(x);
while ((x % p) == 0)
x /= p;
fac(x, st), fac(p, st);
}
inline set<ll> get(ll x)
{
set<ll> st;
fac(x, st);
return st;
}
}
using namespace PR;
inline ll read()
{
ll x = 0, f = 1;
char c = getchar();
while(c < '0' || c > '9')
{
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9')
{
x = x * 10 + c - '0';
c = getchar();
}
return x * f;
}
const int _ = 1e7 + 7;
int T, ans[10007];
ll n, k, dis[_];
map<ll, vector<pair<ll, int> > > mp;
inline ll qpow(ll x, ll y, ll mod)
{
ll res = 1;
while(y)
{
if(y & 1) res = res * x % mod;
x = x * x % mod;
y >>= 1;
}
return res;
}
signed main()
{
T = read();
for(int i = 1; i <= T; ++i)
{
ll x = read();
mp[read()].push_back({x, i});
}
for(auto t : mp)
{
ll k = t.first;
if(k == 1) continue;
auto d = get(k);
if(d.size() == 1)
{
for(auto i : t.second) ans[i.second] = !(i.first % k);
continue;
}
if(d.size() == 2)
{
ll x = *d.begin(), y = *d.rbegin();
for(auto i : t.second)
{
ll c = i.first, id = i.second;
if(c % x == 0)
{
ans[id] = 1;
continue;
}
ll b = c % x * qpow(y, x - 2, x) % x;
ans[id] = b * y <= c;
}
continue;
}
vector<ll> f(d.begin(), d.end());
int x = f[0];
f.erase(f.begin());
for(int i = 0; i < x; ++i) dis[i] = -1;
dis[0] = 0;
priority_queue<pair<ll, int>> q;
q.push({0, 0});
while(!q.empty())
{
auto now = q.top();
q.pop();
int p = now.second;
if(now.first != -dis[p]) continue;
for(auto i : f)
{
int tmp = (p + i) % x;
if(dis[tmp] == -1 || dis[tmp] > dis[p] + i)
{
dis[tmp] = dis[p] + i;
q.push({-dis[tmp], tmp});
}
}
}
for(auto i : t.second) ans[i.second] = dis[i.first % x] <= i.first;
}
for(int i = 1; i <= T; ++i) cout << (ans[i] ? "YES" : "NO") << "\n";
return 0;
}
本文来自博客园,作者:蒟蒻orz,转载请注明原文链接:https://www.cnblogs.com/orzz/p/18122039