[UOJ#221][BZOJ4652][Noi2016]循环之美
[UOJ#221][BZOJ4652][Noi2016]循环之美
试题描述
这部分将提供一个将分数化为对应的小数的方法,如果你已经熟悉这个方法,你不必阅读本提示。
分数可以通过除法,用分子除以分母化为对应的小数。有些分数在除法过程中无法除尽,这样的分数在不断进行的除法过程中余数一定会重复出现。从商数的个位所对应的余数起,设第一次重复出现的余数前两次出现的位置所对应的商数位分别是小数点后第 aa 位和小数点后第 bb 位(特殊地:如果其中一个对应的商数位是个位,则认为 a=0;不妨设 a<b),则其循环部分可以用小数点后第 a+1 位到小数点后第 b 位的循环来表示。
例如:在十进制下,将 5/11 转化为小数时,个位开始的商数依次为 4,5,4,…,对应的余数分别为 6,5,6,…。余数第一次重复出现的位置是个位和小数点后第 2 位,那么 a=0,b=2 即其循环部分可以用小数点第 1 位到第 3 位来表示。表示为:5/11=0.45454545…=0.4˙5˙。
在十进制下,将 1/6 转化为小数时,个位开始的商数依次为 1,6,6,…,对应的余数分别为 4,4,4,…。余数第一次重复出现的位置是小数点后第 1 位和小数点后第 2 位,即其循环部分可以用小数点后第 2 位来表示。表示为:16=0.1666……=0.16˙。
需要注意的是:商数重复出现并不代表进入了循环节。
输入
输出
一行一个整数,表示满足条件的美的数的个数。
输入示例
输出示例
数据规模及约定
见“输入”
题解
根据它的提示,我们可以列一列式子:(令商第 i 位后的余数为 pi)
联立得到
又有 (x, y) = 1,所以得到 km mod y = 1,即 (k, y) = 1。
那么现在题目就是在求:
纯暴力 24 分可以拿到了。
接下来,学习了莫比乌斯反演,我们知道它可以变形
交换一下枚举顺序,得到
那么如果最右边那个Σ能够 O(1) 得到,枚举 d 即可 O(nlogk) 求解,那个Σ求法如下
所以我们只需要预处理出 i = 1, 2, ..., k 时 f(i) 的值即可。至此我们拿到了 84 分。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <algorithm>
using namespace std; int read() {
int x = 0, f = 1; char c = getchar();
while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
return x * f;
} #define maxn 20000001
#define maxk 2010
#define LL long long bool vis[maxn];
int cp, prime[maxn], mu[maxn];
void init() {
mu[1] = 1;
for(int i = 2; i < maxn; i++) {
if(!vis[i]) prime[++cp] = i, mu[i] = -1;
for(int j = 1; i * prime[j] < maxn && j <= cp; j++) {
vis[i*prime[j]] = 1;
if(i % prime[j] == 0){ mu[i*prime[j]] = 0; break; }
mu[i*prime[j]] = -mu[i];
}
}
return ;
} int gcd(int a, int b) { return b ? gcd(b, a % b) : a; } int f[maxk];
int calc(int n, int k) {
return n / k * f[k] + f[n%k];
} int main() {
init(); int n = read(), m = read(), k = read();
for(int i = 1; i <= k; i++) f[i] = f[i-1] + (gcd(i, k) == 1); LL sum = 0;
for(int d = 1; d <= n; d++) if(gcd(d, k) == 1) sum += (LL)mu[d] * (n / d) * calc(m / d, k);
printf("%lld\n", sum); return 0;
}
接着推式子
如果我们能快速求出 g(i, k) 的值,那么可以给后面 [n / d] 以及 f([m / d]) 的值分成 2(sqrt(n) + sqrt(m)) 类并最终高效地求得答案。
考虑 k 的一个质因数 p,那么 k = ptq,[gcd(d,k)=1] 的部分 = [gcd(d,q)=1] 的部分 - [gcd(d,p)>1][gcd(d,q)=1]的部分,所以得到
显然 [gcd(pd,q)=1] = [gcd(p,q)=1][gcd(d,q)=1] = [gcd(d,q)=1]
又因为 [gcd(d,q)=1][gcd(d,p)=1] = [gcd(d,pq)=1],所以,把上式接着变化
这样,我们就可以递归求 g(i, k) 了,每次要么 k 除掉一个它的质因数(除干净),要么 i 变成 [i / p],所以状态数会非常少。
递归边界:i = 0 时 g(i, k) = 0;k = 1 时 g(i, k) 就是莫比乌斯函数的前缀和,学习了杜教筛,就迎刃而解了。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <algorithm>
using namespace std; int read() {
int x = 0, f = 1; char c = getchar();
while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
return x * f;
} #define maxn 1000001
#define maxk 2010
#define MOD 1000007
#define LL long long
#define oo 2147483647 bool vis[maxn];
int cp, prime[maxn], mu[maxn], smu[maxn];
void init() {
mu[1] = 1; smu[1] = 1;
for(int i = 2; i < maxn; i++) {
if(!vis[i]) prime[++cp] = i, mu[i] = -1;
for(int j = 1; i * prime[j] < maxn && j <= cp; j++) {
vis[i*prime[j]] = 1;
if(i % prime[j] == 0){ mu[i*prime[j]] = 0; break; }
mu[i*prime[j]] = -mu[i];
}
smu[i] = smu[i-1] + mu[i];
}
return ;
} int gcd(int a, int b) { return b ? gcd(b, a % b) : a; } int f[maxk];
int calc(int n, int k) {
return n / k * f[k] + f[n%k];
} struct Hash {
int ToT, head[MOD], nxt[maxn], num[maxn], num2[maxn], val[maxn];
Hash() { ToT = 0; memset(head, 0, sizeof(head)); }
void Insert(int x, int v) {
int u = x % MOD;
nxt[++ToT] = head[u]; num[ToT] = x; val[ToT] = v; head[u] = ToT;
return ;
}
void Insert2(int x1, int x2, int v) {
int u = ((LL)x1 * 233 + x2) % MOD;
nxt[++ToT] = head[u]; num[ToT] = x1; num2[ToT] = x2; val[ToT] = v; head[u] = ToT;
return ;
}
int Find(int x) {
int u = x % MOD;
for(int e = head[u]; e; e = nxt[e]) if(num[e] == x) return val[e];
return 0;
}
int Find2(int x1, int x2) {
int u = ((LL)x1 * 233 + x2) % MOD;
for(int e = head[u]; e; e = nxt[e]) if(num[e] == x1 && num2[e] == x2) return val[e];
return oo;
}
} hh, hh2; int getsum(int n) {
if(n < maxn) return smu[n];
if(hh.Find(n)) return hh.Find(n);
int sum = 1;
for(int i = 2, lst; i <= n; i = lst + 1) {
lst = n / (n / i);
sum -= getsum(n / i) * (lst - i + 1);
}
hh.Insert(n, sum);
return sum;
} int fir_p[maxk], lst_q[maxk];
int Find(int n, int k) {
if(!n) return 0;
if(k == 1) return getsum(n);
if(hh2.Find2(n, k) < oo) return hh2.Find2(n, k);
int p = fir_p[k], q = lst_q[k];
int tmp = Find(n, q) + Find(n / p, p * q);
hh2.Insert2(n, k, tmp);
return tmp;
} int main() {
init(); int n = read(), m = read(), k = read();
for(int i = 1; i <= k; i++) f[i] = f[i-1] + (gcd(i, k) == 1); for(int K = 2; K <= k; K++)
for(int i = 1; i <= cp; i++) if(K % prime[i] == 0) {
fir_p[K] = prime[i];
lst_q[K] = K; while(lst_q[K] % fir_p[K] == 0) lst_q[K] /= fir_p[K];
break;
}
LL sum = 0;
for(int i = 1, lst; i <= min(n, m); i = lst + 1) {
lst = min(n / (n / i), m / (m / i));
sum += (LL)(Find(lst, k) - Find(i - 1, k)) * (n / i) * calc(m / i, k);
}
printf("%lld\n", sum); return 0;
}
顺便补一下杜教筛的核心公式:
然后我们就可以通过对 [n / i] 的值分类递归求出 F(n) 了(第二行第一个等号画画表理解吧。。。)
其实杜教筛适用于所有狄利克雷卷积非常好算的数论函数。
[UOJ#221][BZOJ4652][Noi2016]循环之美的更多相关文章
- bzoj4652 [Noi2016]循环之美
Description 牛牛是一个热爱算法设计的高中生.在他设计的算法中,常常会使用带小数的数进行计算.牛牛认为,如果在k进制下,一个数的小数部分是纯循环的,那么它就是美的.现在,牛牛想知道:对于已知 ...
- BZOJ4652: [Noi2016]循环之美(莫比乌斯反演,杜教筛)
Description 牛牛是一个热爱算法设计的高中生.在他设计的算法中,常常会使用带小数的数进行计算.牛牛认为,如果在 k 进制下,一个数的小数部分是纯循环的,那么它就是美的.现在,牛牛想知道:对 ...
- BZOJ4652 NOI2016循环之美(莫比乌斯反演+杜教筛)
因为要求数值不同,不妨设gcd(x,y)=1.由提示可以知道,x/y是纯循环小数的充要条件是x·klen=x(mod y).因为x和y互质,两边同除x,得klen=1(mod y).那么当且仅当k和y ...
- BZOJ4652 [Noi2016]循环之美 【数论 + 莫比乌斯反演 + 杜教筛】
题目链接 BZOJ 题解 orz 此题太优美了 我们令\(\frac{x}{y}\)为最简分数,则\(x \perp y\)即,\(gcd(x,y) = 1\) 先不管\(k\)进制,我们知道\(10 ...
- luogu 1587 [NOI2016]循环之美
LINK:NOI2016循环之美 这道题是 给出n m k 求出\(1\leq i\leq n,1\leq j\leq m\) \(\frac{i}{j}\)在k进制下是一个纯循环的. 由于数值相同的 ...
- UOJ #221 【NOI2016】 循环之美
题目链接:循环之美 这道题感觉非常优美--能有一个这么优美的题面和较高的思维难度真的不容易-- 为了表示方便,让我先讲一下两个符号.\([a]\)表示如果\(a\)为真,那么返回\(1\),否则返回\ ...
- UOJ#221. 【NOI2016】循环之美 数论,杜教筛
原文链接www.cnblogs.com/zhouzhendong/p/UOJ221.html 题解 首先把题目转化为求 \[\sum_{x=1}^n \sum_{y=1}^m [\gcd(x,y) = ...
- 并不对劲的bzoj4652:loj2085:uoj221:p1587:[NOI2016]循环之美
题目大意 对于已知的十进制数\(n\)和\(m\),在\(k\)进制下,有多少个数值上互不相等的纯循环小数,可以用\(x/y\)表示,其中 \(1\leq x\leq n,1\leq y\leq m\ ...
- [NOI2016]循环之美
Description 牛牛是一个热爱算法设计的高中生.在他设计的算法中,常常会使用带小数的数进行计算.牛牛认为,如果在 k 进制下,一个数的小数部分是纯循环的,那么它就是美的.现在,牛牛想知道:对 ...
随机推荐
- Android Theme.Dialog 到光 AppCompatDialog
我用在我的 style.xml 作为主要应用程序主题 <style name="AppTheme" parent="Theme.AppCompat.Light&qu ...
- 起学习iOS开发专用词汇
今天的单词分别是: l Asynchronous 形容词 异步的 n 副词形式: asynchronously 异步地 n 缩写:ASYNC n 反义词:synchronous 形容词同步 ...
- (一)maven之创建一个maven项目
为什么要使用Maven? 1. maven使用的是本地仓库存储jar,所有项目都会共用仓库中的同一份jar. 2. Spring core.jar必须同时引用版本兼容的common-logging ...
- poj1142Smith Numbers质因子分解
题意:一个数不是质数,其质因子的每位加起来等于该数的每位加起来. /* 题意:一个数的所有质因子的每位相加起来等于该数的每位相加起来且该数不能是质数,那么就是史密斯数 tip:对于分解质因子,只需要判 ...
- 解决因为手机设置字体大小导致h5页面在webview中变形的BUG
首先,我们做了一个H5页面,在各种手机浏览器中打开都没问题.我们采用了rem单位进行布局,通过JS来动态计算网页的视窗宽度,动态设置html的font-size,一切都比较完美. 这时候,你自信满满的 ...
- Asp.Net Core 进阶(二) —— 集成Log4net
Asp.Net Core 支持适用于各种内置日志记录API,同时也支持其他第三方日志记录.在我们新建项目后,在Program 文件入口调用了CreateDefaultBuilder,该操作默认将添加以 ...
- C++基础:虚函数、重载、覆盖、隐藏<转>
转自:http://www.2cto.com/kf/201404/291772.html 虚函数总是跟多态联系在一起,引入虚函数可以使用基类指针对继承类对象进行操作! 虚函数:继承接口(函数名,参数, ...
- 一个小笔记(5):A*算法
A-Star算法是一种静态路网中求解最短路径最有效的直接搜索方法其实百科有 http://baike.baidu.com/link?url=CvmkWQIAmztYgMq3Nk1WyWkDiC0koV ...
- DOM事件总结
1.DOM事件: DOM0: element.onclick=function(){} DOM2: element.addEventListener(‘click’,function(){}) add ...
- 【动态规划】bzoj1044: [HAOI2008]木棍分割
需要滚动优化或者short int卡空间 Description 有n根木棍, 第i根木棍的长度为Li,n根木棍依次连结了一起, 总共有n-1个连接处. 现在允许你最多砍断m个连接处, 砍完后n根木棍 ...