[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" ...
随机推荐
- Vue指令1:v-text及v-html
v-text: //插入一段文本<div id="app"> <p v-text="message"></p></di ...
- JAVA程序员面试笔试宝典4
1.HTTP中GET与POST方法有什么区别? GET方法上传数据时,数据添加在URL后面.同时,数据大小有限制,通常在1024Byte左右.POST方法传递数据是通过HTTP请求的附件进行的,传递的 ...
- JAVA程序员面试笔试宝典3
1.什么是线程?它与进程有什么区别?为什么要使用多线程 线程是指程序在执行过程中,能够执行程序代码的一个执行单元.进程是指一段正在执行的程序. 使用多线程可以减少程序的相应时间 与进程相比,线程的创建 ...
- Python使用Flask框架,结合Highchart处理csv数据(引申-从文件获取数据--从数据库获取数据)
参考链接:https://www.highcharts.com.cn/docs/process-text-data-file 1.javascript代码 var options = { chart: ...
- java 数组排序并去重
https://www.cnblogs.com/daleyzou/p/9522533.htmlimport java.lang.reflect.Array;import java.util.Array ...
- linux下的进程
一.进程的基础: 1.程序:程序是一些保存在磁盘上的指令的有序集合: 2.进程:进程是程序的一次执行过程: 3.进程与程序的关系:①.程序是静态的,进程是动态的: ②.一个程序可以对应多个进程: ...
- HDU 5115 (2014ACM/ICPC亚洲区北京站) D题(Dire Wolf)
题目传送门 设dp[i][j]为杀掉区间i到j之间的狼需要付出的最小代价,那么dp[i][j]=min{dp[i][k-1]+dp[k+1][j]+a[k]+b[i-1]+b[j+1]} Java代码 ...
- dp专题备忘录
hdu 1024:基础dp题 hdu 1029:主元素问题,很快的解法,计数器 hdu 1069:LIS hdu 1074:数位dp,数位dp基础 hdu 1257:简单LIS,要仔细分析为什么是求最 ...
- log 框架 之间的关系
日志框架分为两大部分 一部分是日志框架的抽象层,一部分是日志框架的具体实现 slf4j: 日志框架的抽象层 log4j,logback 日志框架的具体实现 如上图所示: slf4j的具体实现是:slf ...
- Ioc思想
DIP: Dependency Inversion Principle 依赖倒转原则 高层次组件不应该依赖于低层次组件,二者均应该依赖于接口.抽象不应该依赖于细节,细节应该依赖于抽象. IOC:Inv ...