[Codeforces 485F] Oppa Funcan Style Remastered
[题目链接]
https://codeforces.com/contest/986/problem/F
[算法]
不难发现 , 每个人都在且仅在一个简单环中 , 设这些环长的长度分别为
A1, A2 , A3 ... Alen, 那么有 :
1. A1 + A2 + A3 + .. + Alen = n
2. A1 , A2 , .. Alen为k的因子且大于或等于2
显然 , 每一个k的因数都可以分成若干个k的质因子之和 , 因此我们可以将问题转化为求是否存在 :
B1P1 + B2P2 + ... BmPm = n (其中,m为质因子的个数)
当m = 0时, 显然无解
当m = 1时 ,若n为P1的倍数 , 则有解 , 否则无解
当m = 2时 , 问题就转化为判断一个形如 :Ax + By = C , GCD(A,B) = 1的不定方程是否有非负整数解 , 我们可以用拓展欧几里得或其他算法解决 , 不再赘述
当m >= 3时 , 显然 , 最小的质因子一定小于等于k ^ (1 / 3), k最大时达到10 ^ 15 , 因此 , k ^ (1 / 3)不会超过10 ^ 5 , 我们不妨建10^5个点 ,
若(i + Pi) mod P1 = j mod P1 , 则从i向j连一条权值为Pi的边。
然后我们从0号点开始单源最短路 , 求得的最短路Dist[i]表示通过k的质因子组合出的,模P1余i的数中最小的 , 显然 , 若n >= Dist[n mod P1] , 问题有解 , 否则无解。
下面我们分析整个算法的时间复杂度 :
令Q = 50( 不同的k的个数 )
首先 , 为了减少在分解质因数上花费的时间 , 我们需要预处理质数 , 这将花费我们O( sqrt(K) ) )的时间 , 其中sqrt表示开根号
对于每个询问 , 我们需要将k分解质因数 , 我们需要花费O(Q * sqrt(K) / log(K))的时间 , 其中sqrt表示开根号
当m <= 2时我们需花费O(1) - O(logN)的时间 , 共需O(TlogN)的时间
当m >= 3时我们需要花费O(Q * k ^( 1 / 3) * logk)计算单源最短路( 需使用高效的Dijkstra + 堆算法 )
综上 , 总时间复杂度为 : O( sqrt(k) + Q * ( sqrt(k) / log(k) + k ^ (1 / 3)logk ) + TlogN) , 可以通过此题
[代码]
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll MAXN = 1e18;
const ll MAXK = 1e15;
const ll INF = 4e18;
const int MAXV = 3.2e7 + ;
const int MAXP = 2e6 + ;
const int MAXF = 1e5 + ;
const int MAXQ = ;
const int MAXLOG = ; ll n,k,tot,q;
int f[MAXV],prime[MAXP],cnt[MAXQ + ];
ll p[MAXQ + ][MAXLOG],dist[MAXQ + ][MAXF];
ll mem[MAXQ];
bool visited[MAXP]; template <typename T> inline void read(T &x)
{
ll f = ; x = ;
char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
for (; isdigit(c); c = getchar()) x = (x << ) + (x << ) + c - '';
x *= f;
}
inline ll exp_mod(ll a,ll n,ll p)
{
ll res = , b = a;
while (n > )
{
if (n & ) res = res * b % p;
b = b * b % p;
n >>= ;
}
return res;
} int main()
{ int T;
read(T);
for (int i = ; i < MAXV; i++)
{
if (!f[i]) prime[++tot] = f[i] = i;
for (int j = ; j <= tot; j++)
{
int tmp = i * prime[j];
if (tmp >= MAXV) break;
f[tmp] = prime[j];
if (f[i] == prime[j]) break;
}
}
while (T--)
{
read(n); read(k);
if (k == )
{
printf("NO\n");
continue;
}
int pos = ;
for (int i = ; i <= q; i++)
if (mem[i] == k) pos = i;
if (!pos)
{
pos = ++q;
mem[pos] = k;
cnt[pos] = ;
for (int i = ; 1ll * prime[i] * prime[i] <= k; i++)
{
if (k % prime[i] == )
{
p[pos][++cnt[pos]] = prime[i];
while (k % prime[i] == ) k /= prime[i];
}
}
if (k != ) p[pos][++cnt[pos]] = k;
if (cnt[pos] >= )
{
for (int i = ; i < p[pos][]; i++)
{
dist[pos][i] = INF;
visited[i] = false;
}
dist[pos][] = ;
static priority_queue< pair<ll,int> > q;
q.push(make_pair(,));
while (!q.empty())
{
int u = q.top().second;
q.pop();
if (visited[u]) continue;
visited[u] = true;
for (int i = ; i <= cnt[pos]; i++)
{
int to = (u + p[pos][i]) % p[pos][];
int w = p[pos][i];
if (dist[pos][u] + w < dist[pos][to])
{
dist[pos][to] = dist[pos][u] + w;
q.push(make_pair(-dist[pos][to],to));
}
}
}
}
}
if (cnt[pos] == )
{
if (n % p[pos][] == )
{
printf("YES\n");
continue;
} else
{
printf("NO\n");
continue;
}
}
if (cnt[pos] == )
{
ll b = n % p[pos][] * exp_mod(p[pos][] , p[pos][] - ,p[pos][]) % p[pos][];
if (b * p[pos][] <= n) printf("YES\n");
else printf("NO\n");
continue;
}
int val = n % p[pos][];
if (n >= dist[pos][val]) printf("YES\n");
else printf("NO\n");
} return ; }
[Codeforces 485F] Oppa Funcan Style Remastered的更多相关文章
- Codeforces 986F - Oppa Funcan Style Remastered(同余最短路)
Codeforces 题面传送门 & 洛谷题面传送门 感谢此题教会我一个东西叫做同余最短路(大雾 首先这个不同 \(k\) 的个数 \(\le 50\) 这个条件显然是让我们对每个 \(k\) ...
- CF986F Oppa Funcan Style Remastered
CF986F Oppa Funcan Style Remastered 不错的图论转化题! 题目首先转化成:能否用若干个k的非1因数的和=n 其次,因数太多,由于只是可行性,不妨直接都用质因子来填充! ...
- 「CF986F」 Oppa Funcan Style Remastered
「CF986F」 Oppa Funcan Style Remastered Link 首先发现分解成若干个 \(k\) 的因数很蠢,事实上每个因数都是由某个质因子的若干倍组成的,所以可以将问题转换为分 ...
- [CF986F]Oppa Funcan Style Remastered[exgcd+同余最短路]
题意 给你 \(n\) 和 \(k\) ,问能否用 \(k\) 的所有 \(>1\) 的因子凑出 \(n\) .多组数据,但保证不同的 \(k\) 不超过 50 个. \(n\leq 10^{1 ...
- codeforces986F Oppa Funcan Style Remastered【线性筛+最短路】
容易看出是用质因数凑n 首先01个因数的情况可以特判,2个的情况就是ap1+bp2=n,b=n/p2(mod p1),这里的b是最小的特解,求出来看bp2<=n则有解,否则无解 然后剩下的情况最 ...
- CodeForces 150E: Freezing with Style
题目传送门:CF150E. 据说这个傻逼题还有一个 \(\log\) 的做法,但是我还不会. 题意简述: 给定一棵 \(n\)(\(2\le n\le 10^5\))个点的树,边有边权. 定义一条路径 ...
- 一句话题解&&总结
CF79D Password: 差分.两点取反,本质是匹配!最短路+状压DP 取反是套路,匹配是发现可以把操作进行目的化和阶段化,从而第二次转化问题. 且匹配不会影响别的位置答案 sequence 计 ...
- CodeForces - 344B Simple Molecules (模拟题)
CodeForces - 344B id=46665" style="color:blue; text-decoration:none">Simple Molecu ...
- CodeForces - 344D Alternating Current (模拟题)
id=46667" style="color:blue; text-decoration:none">CodeForces - 344D id=46667" ...
随机推荐
- vi 命令学习(二)
[选中文本(可视模式)] v 可视模式 从光标位置开始按正常模式选择文本 V 可视行模式 选中光标经过的完整行 ctrl + v 可视块模式 垂直方向选中文本 [ 撤销和恢复撤销] u undo 撤销 ...
- RabbitMQ系列(四)--消息如何保证可靠性传输以及幂等性
一.消息如何保证可靠性传输 1.1.可能出现消息丢失的情况 1.Producer在把Message发送Broker的过程中,因为网络问题等发生丢失,或者Message到了Broker,但是出了问题,没 ...
- 06C语言运算符
C语言运算符 算术运算符 运算符 描述 + 把两个操作数相加 - 从第一个操作数中减去第二个操作数 * 把两个操作数相乘 / 分子除以分母 % 取模运算符,整除后的余数 ++ 自增运算符,整数值增加 ...
- php file_get_contents函数分段读取大记事本或其它文本文件
当我们遇到文本文件体积很大时,比如超过几十M甚至几百M几G的大文件,用记事本或者其它编辑器打开往往不能成功,因为他们都需要把文件内容全部放到内存里面,这时就会发生内存溢出而打开错误,遇到这种情况我们可 ...
- vue-cli项目结构分析
总体框架 一个vue-cli的项目结构如下,其中src文件夹是需要掌握的,所以本文也重点讲解其中的文件,至于其他相关文件,了解一下即可. 文件结构细分 1.build——[webpack配置] bui ...
- buf.readDoubleBE()
buf.readDoubleBE(offset[, noAssert]) buf.readDoubleLE(offset[, noAssert]) offset {Number} 0 <= of ...
- Mysql Group by 分组取最小的实现方法
表结构如下图:
- 使用 XMLHttpRequest实现Ajax
[XMLHttpRequest的概述] 1.XMLHttpRequest最早是在IE5中以ActiveX组件的形式实现的.非W3C标准 2.创建XMLHttpRequest对象(由于非标准所以实现方法 ...
- 判断项目中是否有slf4j的实现类
/** * 判断项目中是否有slf4j的实现类 */ @org.junit.Test public void test() { try { Enumeration<URL> resourc ...
- hammerjs & Swiper & touch & gesture
hammerjs https://hammerjs.github.io/getting-started/ http://hammerjs.github.io/recognizer-swipe/ Swi ...