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 ...
随机推荐
- dedecms织梦上下页标签和CSS
模板中的分页部分源码: <div class="pagination-wrapper" style= "font-size:20pt;color:red;text- ...
- spring javaconfig druidsource
package dataConfig; import java.sql.SQLException; import org.springframework.context.annotation.Bean ...
- 人脸检测识别,人脸检测,人脸识别,离线检测,C#源码
百度网盘地址 微云地址 使用虹软人工智能开放平台技术开发完成
- 用存储过程向数据库添加大量数据【mysql】
预分配ID的设计,需要先为数据库生成大量的数据.比如对用户ID有要求的系统,那么用户ID就要预先生成. 通过python,php,c/c++/c#,js等程序生成也是可以,但需要这些程序环境,而且单条 ...
- Debain/Ubuntu/Deepin 下使用 ss
如果你有一台 ss 的服务器,在 Debian Like 的环境下要如何***呢? 安装 ss 客户端 如果还没安装 pip 就得先安装 sudo apt-get install python-pip ...
- 【RL-TCPnet网络教程】第2章 嵌入式网络协议栈基础知识
第2章 嵌入式网络协议栈基础知识 本章教程为大家介绍嵌入式网络协议栈基础知识,本章先让大家有一个全面的认识,后面章节中会为大家逐一讲解用到的协议. 基础知识整理自百度百科,wiki百科等 ...
- NPM -- 初探--01
NPM是随同NodeJS一起安装的包管理工具,能解决NodeJS代码部署上的很多问题,常见的使用场景有以下几种: 允许用户从NPM服务器下载别人编写的第三方包到本地使用. 允许用户从NPM服务器下载并 ...
- Diagnostics: File file:/tmp/spark-95cbb984-da28-4784-8b99-eb83ad74437f/__spark_libs__1421840316395076250.zip does not exist
搭建spark环境,测试在yarn 上运行spark shell的时候出现的错误:Diagnostics: File file:/tmp/spark-95cbb984-da28-4784-8b99-e ...
- Windows下查看硬连接引用技术
Win10有了bash,可以方便的进入并用ll查看文件的硬连接数. 但是用powershell直接查看就比较麻烦了,比较曲折的找到了方法: fsutil hardlink list [filename ...
- [题解] P2513 [HAOI2009]逆序对数列
动态规划,卡常数 题目地址 设\(F[X][Y]\)代表长度为\(X\)的序列,存在\(Y\)组逆序对的方案数量. 考虑\(F[X][i]\)向\(F[X+1][i]\)转移: 把数字\(X+1\)添 ...