LOJ#2085 循环之美



解:首先看这个纯循环到底是什么玩意.....
经过一番打表,发现纯循环小数就是分母与进制互质的既约分数。
#include <bits/stdc++.h>
std::bitset<> vis;
inline bool check(int x, int y) { /// x / y
//printf("x = %d y = %d \n", x, y);
vis.reset();
int rest = x % y;
if(!rest) return true;
int op = rest;
vis[op] = ;
//printf("op = %d \n", op);
while(true) {
rest *= ;
int r = rest % y;
//printf("r = %d \n", r);
if(vis[r]) {
//printf("return %d = %d \n", r, op);
return r == op;
}
vis[r] = ;
rest = r;
}
return false;
}
int gcd(int a, int b) {
if(!b) return a;
return gcd(b, a % b);
}
int main() {
int n;
scanf("%d", &n);
for(int i = ; i <= n; i++) {
for(int j = ; j <= n; j++) {
if(gcd(i, j) == ) printf("%d ", (int)check(i, j));
else printf(" ");
}
puts("");
}
return ;
}
打表程序
那么就有了一个很显然的O(nmlogV)的做法...直接暴力枚举然后检验。实测24分。
#include <bits/stdc++.h>
int gcd(int a, int b) {
if(!b) return a;
return gcd(b, a % b);
}
int main() {
int n, m, k, ans = ;
scanf("%d%d%d", &n, &m, &k);
if(1ll * n * m > ) return ;
for(int i = ; i <= m; i++) {
if(gcd(k, i) > ) continue;
for(int j = ; j <= n; j++) {
ans += gcd(i, j) == ;
}
}
printf("%d\n", ans);
return ;
}
24分暴力
然后发现最里面那句话有点像phi...仔细思考之后发现不是。
现在开始鬼畜时间...推柿子。

其中有两步转化,分别是把[x=1]用∑μ代替和把[1=(id,k)]用[1=(i,k)][1=(d,k)]代替。
于是考虑最后这个式子,发现有个东西[1=(a,k)],于是设这个东西为g(x),它的前缀和为f(x)。又令F为μ·g的前缀和。
那么答案就是下式:

这个东西显然可以分块一波。后两项可以O(1)算,前面的可以线性预处理。于是我们有个O(n)的算法。可以获得84分。
#include <bits/stdc++.h> typedef long long LL;
const int N = ; int miu[N], p[N], top, f[N], phi[N], n, m, k, F[N];
bool vis[N]; inline void getp(int n) {
phi[] = miu[] = ;
for(int i = ; i <= n; i++) {
if(!vis[i]) {
p[++top] = i;
miu[i] = -;
phi[i] = i - ;
}
for(int j = ; j <= top && i * p[j] <= n; j++) {
vis[i * p[j]] = ;
if(i % p[j] == ) {
//miu[i * p[j]] = 0;
phi[i * p[j]] = phi[i] * p[j];
break;
}
phi[i * p[j]] = phi[i] * (p[j] - );
miu[i * p[j]] = -miu[i];
}
}
return;
} int gcd(int a, int b) {
if(!b) return a;
return gcd(b, a % b);
} inline void prework() {
for(int i = ; i <= k; i++) {
f[i] = f[i - ] + (gcd(i, k) == );
F[i] = F[i - ] + (f[i] - f[i - ]) * miu[i];
}
int len = std::min(n, m);
for(int i = k + ; i <= len; i++) {
f[i] = f[k] * (i / k) + f[i % k];
F[i] = F[i - ] + (f[i] - f[i - ]) * miu[i];
}
return;
} inline int getf(int x) {
if(x <= k) return f[x];
return f[k] * (x / k) + f[x % k];
} int main() {
LL ans = ;
scanf("%d%d%d", &n, &m, &k);
if(1ll * n * m < 1e9) {
for(int i = ; i <= m; i++) {
if(gcd(k, i) > ) continue;
for(int j = ; j <= n; j++) {
ans += gcd(i, j) == ;
}
}
printf("%lld\n", ans);
return ;
}
if(n < N) {
getp(n);
prework();
int len = std::min(n, m);
for(int i = , j; i <= len; i = j + ) {
j = std::min(n / (n / i), m / (m / i));
/// [i, j]
ans += 1ll * (F[j] - F[i - ]) * (n / i) * getf(m / i);
}
printf("%lld\n", ans);
}
return ;
}
84分代码
接下来补个k = 2 / 3的部分分。严格来说应该能应付k是质数的情况,然而后面k都是合数....
推倒过程几乎跟上面一样,最后得到这个东西:

考虑怎么计算后面那个求和符号。当d和k不互质(d是k的倍数)的时候,答案显然是0。否则令t = i / d,答案就是与k互质的t个个数。这个东西我们可以用maxt - maxt / k来O(1)计算。
#include <bits/stdc++.h> typedef long long LL;
const int N = ; int miu[N], p[N], top, f[N], phi[N], n, m, k, F[N];
bool vis[N]; inline void getp(int n) {
phi[] = miu[] = ;
for(int i = ; i <= n; i++) {
if(!vis[i]) {
p[++top] = i;
miu[i] = -;
phi[i] = i - ;
}
for(int j = ; j <= top && i * p[j] <= n; j++) {
vis[i * p[j]] = ;
if(i % p[j] == ) {
//miu[i * p[j]] = 0;
phi[i * p[j]] = phi[i] * p[j];
break;
}
phi[i * p[j]] = phi[i] * (p[j] - );
miu[i * p[j]] = -miu[i];
}
}
return;
} int gcd(int a, int b) {
if(!b) return a;
return gcd(b, a % b);
} inline int calc(int d) {
if((d % k) == ) {
return ;
}
d = m / d;
return d - d / k;
} inline void prework() {
for(int i = ; i <= k; i++) {
f[i] = f[i - ] + (gcd(i, k) == );
F[i] = F[i - ] + (f[i] - f[i - ]) * miu[i];
}
int len = std::min(n, m);
for(int i = k + ; i <= len; i++) {
f[i] = f[k] * (i / k) + f[i % k];
F[i] = F[i - ] + (f[i] - f[i - ]) * miu[i];
}
return;
} inline int getf(int x) {
if(x <= k) return f[x];
return f[k] * (x / k) + f[x % k];
} int main() {
LL ans = ;
scanf("%d%d%d", &n, &m, &k);
if(1ll * n * m < 1e9) {
for(int i = ; i <= m; i++) {
if(gcd(k, i) > ) continue;
for(int j = ; j <= n; j++) {
ans += gcd(i, j) == ;
}
}
printf("%lld\n", ans);
return ;
}
if((k == || k == ) && (n <= )) {
getp(n);
int len = std::min(n, m);
for(int i = ; i <= len; i++) {
ans += 1ll * miu[i] * (n / i) * calc(i);
}
printf("%lld\n", ans);
return ;
}
/*if(n < N) {
getp(n);
prework();
int len = std::min(n, m);
for(int i = 1, j; i <= len; i = j + 1) {
j = std::min(n / (n / i), m / (m / i));
/// [i, j]
ans += 1ll * (F[j] - F[i - 1]) * (n / i) * getf(m / i);
}
printf("%lld\n", ans);
}*/
return ;
}
40分代码
LOJ#2085 循环之美的更多相关文章
- LOJ 2085: 洛谷 P1587: bzoj 4652: 「NOI2016」循环之美
题目传送门:LOJ #2085. 两个月之前做的傻题,还是有必要补一下博客. 题意简述: 求分子为不超过 \(n\) 的正整数,分母为不超过 \(m\) 的正整数的所有互不相等的分数中,有多少在 \( ...
- UOJ #221 【NOI2016】 循环之美
题目链接:循环之美 这道题感觉非常优美--能有一个这么优美的题面和较高的思维难度真的不容易-- 为了表示方便,让我先讲一下两个符号.\([a]\)表示如果\(a\)为真,那么返回\(1\),否则返回\ ...
- 【BZOJ4652】【NOI2016】循环之美(莫比乌斯反演,杜教筛)
[BZOJ4652]循环之美(莫比乌斯反演,杜教筛) 题解 到底在求什么呢... 首先不管他\(K\)进制的问题啦,真是烦死啦 所以,相当于有一个分数\(\frac{i}{j}\) 因为值要不相等 所 ...
- LibreOJ2085 - 「NOI2016」循环之美
Portal Description 给出\(n,m(n,m\leq10^9)\)和\(k(k\leq2000)\),求在\(k\)进制下,有多少个数值不同的纯循环小数可以表示成\(\dfrac{x} ...
- [UOJ#221][BZOJ4652][Noi2016]循环之美
[UOJ#221][BZOJ4652][Noi2016]循环之美 试题描述 牛牛是一个热爱算法设计的高中生.在他设计的算法中,常常会使用带小数的数进行计算.牛牛认为,如果在 k 进制下,一个数的小数部 ...
- 「NOI2016」循环之美
P1587 [NOI2016]循环之美 题目描述 牛牛是一个热爱算法设计的高中生.在他设计的算法中,常常会使用带小数的数进行计算.牛牛认为,如果在 $k$ 进制下,一个数的小数部分是纯循环的,那么它就 ...
- 「NOI2016」循环之美 解题报告
「NOI2016」循环之美 对于小数\(\frac{a}{b}\),如果它在\(k\)进制下被统计,需要满足要求并且不重复. 不重复我们确保这个分数是最简分数即\((a,b)=1\) 满足要求需要满足 ...
- luogu 1587 [NOI2016]循环之美
LINK:NOI2016循环之美 这道题是 给出n m k 求出\(1\leq i\leq n,1\leq j\leq m\) \(\frac{i}{j}\)在k进制下是一个纯循环的. 由于数值相同的 ...
- *LOJ#2085. 「NOI2016」循环之美
$n \leq 1e9,m \leq 1e9,k \leq 2000$,求$k$进制下$\frac{x}{y}$有多少种不同的纯循环数取值,$1 \leq x \leq n,1 \leq y \leq ...
随机推荐
- int-Integer-String之间的转换方式
1.int和Integer之间的转换: 1) int----->Integer ①自动装箱 ②Integer的构造方法 ③调用Integer的静态方法:static Integer valu ...
- 验证码的设计与记住我存储用户名密码cookie的技术及单选按钮选择登录人身份的实现
login.jsp页面 <head> <script type="text/javascript" src="js/captcha.js"&g ...
- 【设计模式】单例模式 Singleton Pattern
通常我们在写程序的时候会碰到一个类只允许在整个系统中只存在一个实例(Instance) 的情况, 比如说我们想做一计数器,统计某些接口调用的次数,通常我们的数据库连接也是只期望有一个实例.Windo ...
- java.sql.SQLException: The server time zone value '???ú±ê×??±??' is unrecognized or represents more than one time zone.
[报错信息] [百度翻译] 服务器时区值'???ú±ê×??±??'无法识别或表示多个时区.如果要利用时区支持,必须配置服务器或JDBC驱动程序(通过ServerTimeZone配置属性),以使用更具 ...
- Socket 通讯原理
Socket是什么呢? Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口.在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后 ...
- ORA-04030: out of process memory when trying to allocate 152 bytes (Logminer LCR c,krvtadc)
今天使用LogMiner找回误更新的数据时,查询v$logmnr_contents时,遇到了"ORA-04030: out of process memory when trying to ...
- There is already an object named '#xxxx' in the database.
这个案例是前几天同事遇到的一个案例,在存储过程中"删除"了一个临时表,然后重新创建这个临时表时遇到"There is already an object named 'x ...
- C#格式化
格式化表示的一般格式 { N [ , M ] [ :格式码 ] } N: 指定参数序列中的输出序号,比如{0} , {1}, {2}等. M: 指定参数输出的最小长度. 如果参数长度小于M,则空格填 ...
- DVWA-命令执行学习笔记
DVWA-命令执行 原理: web服务器没有对用户提交的数据进行严格的过滤,造成调用操作系统的命令或者在操作系统恶意拼接拼接命令,以达到攻击者的目的. 1.将DVWA的级别设置为low 1.2查看源代 ...
- LeetCode算法题-Min Cost Climbing Stairs(Java实现)
这是悦乐书的第307次更新,第327篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第176题(顺位题号是746).在楼梯上,第i步有一些非负成本成本[i]分配(0索引). ...