解:首先看这个纯循环到底是什么玩意.....

经过一番打表,发现纯循环小数就是分母与进制互质的既约分数。

 #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 循环之美的更多相关文章

  1. LOJ 2085: 洛谷 P1587: bzoj 4652: 「NOI2016」循环之美

    题目传送门:LOJ #2085. 两个月之前做的傻题,还是有必要补一下博客. 题意简述: 求分子为不超过 \(n\) 的正整数,分母为不超过 \(m\) 的正整数的所有互不相等的分数中,有多少在 \( ...

  2. UOJ #221 【NOI2016】 循环之美

    题目链接:循环之美 这道题感觉非常优美--能有一个这么优美的题面和较高的思维难度真的不容易-- 为了表示方便,让我先讲一下两个符号.\([a]\)表示如果\(a\)为真,那么返回\(1\),否则返回\ ...

  3. 【BZOJ4652】【NOI2016】循环之美(莫比乌斯反演,杜教筛)

    [BZOJ4652]循环之美(莫比乌斯反演,杜教筛) 题解 到底在求什么呢... 首先不管他\(K\)进制的问题啦,真是烦死啦 所以,相当于有一个分数\(\frac{i}{j}\) 因为值要不相等 所 ...

  4. LibreOJ2085 - 「NOI2016」循环之美

    Portal Description 给出\(n,m(n,m\leq10^9)\)和\(k(k\leq2000)\),求在\(k\)进制下,有多少个数值不同的纯循环小数可以表示成\(\dfrac{x} ...

  5. [UOJ#221][BZOJ4652][Noi2016]循环之美

    [UOJ#221][BZOJ4652][Noi2016]循环之美 试题描述 牛牛是一个热爱算法设计的高中生.在他设计的算法中,常常会使用带小数的数进行计算.牛牛认为,如果在 k 进制下,一个数的小数部 ...

  6. 「NOI2016」循环之美

    P1587 [NOI2016]循环之美 题目描述 牛牛是一个热爱算法设计的高中生.在他设计的算法中,常常会使用带小数的数进行计算.牛牛认为,如果在 $k$ 进制下,一个数的小数部分是纯循环的,那么它就 ...

  7. 「NOI2016」循环之美 解题报告

    「NOI2016」循环之美 对于小数\(\frac{a}{b}\),如果它在\(k\)进制下被统计,需要满足要求并且不重复. 不重复我们确保这个分数是最简分数即\((a,b)=1\) 满足要求需要满足 ...

  8. luogu 1587 [NOI2016]循环之美

    LINK:NOI2016循环之美 这道题是 给出n m k 求出\(1\leq i\leq n,1\leq j\leq m\) \(\frac{i}{j}\)在k进制下是一个纯循环的. 由于数值相同的 ...

  9. *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 ...

随机推荐

  1. OPPO K3在哪里打开USB调试模式的完美方法

    当我们使用pc链接安卓手机的时候,如果手机没有开启USB调试模式,pc则无法成功识别我们的手机,这个时候我们需要找解决方法将手机的USB调试模式打开,今天我们介绍OPPO K3如何开启USB调试模式的 ...

  2. Oracle 时间字段显示不正确,类型错误

    一.知识点 给Oracle的date类型字段设置默认值[设置为当前时间] to_date(to_char(sysdate,'yyyy-mm-dd hh24:mi:ss'),'yyyy-mm-dd hh ...

  3. 常见的异步方式async 和 await

    之前研究过c#的async和await关键字,幕后干了什么,但是不知道为什么找不到相关资料了.现在重新研究一遍,顺便记录下来,方便以后查阅. 基础知识 async 关键字标注一个方法,该方法返回值是一 ...

  4. Numpy库的学习(二)

    今天来继续学习一下Numpy库的使用 接着昨天的内容继续 在Numpy中,我们如果想要进行一个判断使用“==” 我们来看下面的代码 vector = np.array([5,10,15,20,25]) ...

  5. Git - git branch - 查看本地仓分支列表

    索引: 目录索引 参看代码 GitHub: git.txt 一.示例: git branch 二.说明: 该命令将列出本地所有存在分支, 包括 本地独有分支与远端在本地签出的分支, 但是没有签出的远端 ...

  6. postman的简单使用

    Postman简单的使用  什么是Postman 在程序开发中用于调试网络程序或者跟踪网页请求.可以对网页进行简单的基本信息调试.Postman最早是作用chrome浏览器插件存在的,但是2018年初 ...

  7. Cannot connect to WMI Provider & Invalid class [0x80041010]

    数据库服务器(Virtual Machine)所在的Nutanix一台主机由于故障,VM自动切换到另一台主机,切换过程中VM会重新启动,但是早上检查的时候,发现点击SQL Server Configu ...

  8. eslint 代码缩进 报错及解决

    一.背景 使用vue在VScode中正常写的代码,报了一堆的错误,仔细检查,发现都是缩进要么多了要么少了,总之是代码不规范的的报错. 二.原因 百度查了发现代码规范默认缩进2个空格,而VScode默认 ...

  9. Android串口开发

    参考资料: https://www.jianshu.com/p/9249ed03e745 GitHUb地址: https://github.com/AIlll/AndroidSerialPort An ...

  10. uboot的启动过程-FDT

    uboot的启动过程,省略了汇编部分之后,第一个执行函数是board_init_f(),在uboot/common目录的board_f.c中   board_init_f函数,首先初始化了全局数据 # ...