P1587 [NOI2016]循环之美

题目描述

牛牛是一个热爱算法设计的高中生。在他设计的算法中,常常会使用带小数的数进行计算。牛牛认为,如果在 $k$ 进制下,一个数的小数部分是纯循环的,那么它就是美的。现在,牛牛想知道:对于已知的十进制数 $n$ 和 $m$,在 $k$ 进制下,有多少个数值上互不相等的纯循环小数,可以用分数 $\frac xy$ 表示,其中 $1≤x≤n,1≤y≤m$,且 $x,y$是整数。一个数是纯循环的,当且仅当其可以写成以下形式:

$a.\dot{c_1} c_2 c_3 \dots c_{p - 1} \dot{c_p}$

其中,$a$ 是一个整数,$p≥1$;对于 $1≤i≤p$,$c_i$ 是 $k$ 进制下的一位数字。

例如,在十进制下,$0.45454545……=0.\dot {4} \dot {5}$是纯循环的,它可以用 $\frac {5}{11}$、$\frac{10}{22}$ 等分数表示;在十进制下,$0.1666666……=0.1\dot6$则不是纯循环的,它可以用 $1/6$ 等分数表示。需要特别注意的是,我们认为一个整数是纯循环的,因为它的小数部分可以表示成 $0$ 的循环或是 $k-1$ 的循环;而一个小数部分非 $0$ 的有限小数不是纯循环的。

输入输出格式

输入格式:

只有一行,包含三个十进制数N,M,K意义如题所述,保证 1≤n≤10^9,1≤m≤10^9,2≤k≤2000

输出格式:

一行一个整数,表示满足条件的美的数的个数。

输入输出样例

输入样例#1:
复制

2 6 10
输出样例#1:
复制

4

说明

满足条件的数分别是:

1/1=1.0000……
1/3=0.3333……
2/1=2.0000……
2/3=0.6666……

1/1 和 2/2 虽然都是纯循环小数,但因为它们相等,因此只计数一次;同样,1/3 和 2/6 也只计数一次。

这部分将提供一个将分数化为对应的小数的方法,如果你已经熟悉这个方法,你不必阅读本提示。

分数可以通过除法,用分子除以分母化为对应的小数。有些分数在除法过程中无法除尽,这样的分数在不断进行的除法过程中余数一定会重复出现。从商数的个位所对应的余数起,设第一次重复出现的余数前两次出现的位置所对应的商数位分别是小数点后第 a位和小数点后第 b 位(特殊地:如果其中一个对应的商数位是个位,则认为 a=0;不妨设 a<b),则其循环部分可以用小数点后第 a+1位到小数点后第 b位的循环来表示。

例如:在十进制下,将 511转化为小数时,个位开始的商数依次为 4,5,4,…,对应的余数分别为 6,5,6,…。余数第一次重复出现的位置是个位和小数点后第 2 位,那么 a=0,b=2

a=0,b=2即其循环部分可以用小数点第 1位到第 3位来表示。表示为:511=0.45454545…=0.4˙5˙。

在十进制下,将 16 转化为小数时,个位开始的商数依次为 1,6,6,…,对应的余数分别为 4,4,4,…。余数第一次重复出现的位置是小数点后第 1 位和小数点后第 2 位,即其循环部分可以用小数点后第 2 位来表示。表示为:16=0.1666……=0.16˙。

需要注意的是:商数重复出现并不代表进入了循环节。

Kelin的题解

题意:求\(\sum_{x=1}^n\sum_{y=1}^m\frac{x}{y}\)在\(k\)进制下能表示成循环节从第一位小数开始的无限循环小数或整数的最简分数个数

假设\(\frac{x}{y}\)的循环节长度为\(l\),则$ {\frac{xk^l}{y}}={\frac{x}{y}}$。

这里大括号表示其小数部分,意思就是把小数点往后挪\(l\)位,小数部分还是相同。比如\(1.123123\ldots\)小数点往后挪3位变成\(1123.123\ldots\)

参照10进制下小数点往后挪 \(l\) 位就是乘以 \(10^l\),那么 \(k\) 进制下小数点往后挪 \(l\) 位就是乘以 \(k^l\)

\[\{\frac{xk^l}{y}\}=\{\frac{x}{y}\}\\
\Rightarrow \frac{xk^l}{y}-\lfloor\frac{xk^l}{y}\rfloor=\frac{x}{y}-\lfloor\frac{x}{y}\rfloor\\
\Rightarrow xk^l-\lfloor\frac{xk^l}{y}\rfloor*y=x-\lfloor\frac{x}{y}\rfloor*y\\
\Rightarrow xk^l\equiv x\mod y
\]

题目要求最简分数,所以 \(\gcd(x,y)=1\)

\[xk^l\equiv x\mod y\\
\Rightarrow k^l\equiv1\mod y\\
\Rightarrow (k,y)=1\\
\Rightarrow Ans=\sum_{i=1}^n\sum_{j=1}^m[\gcd(i,j)=1][\gcd(j,k)=1]
\]

  • 考虑处理 \([\gcd(i,j)=1]\)

\[Ans=\sum_{i=1}^n\sum_{j=1}^m[\gcd(i,j)=1][\gcd(j,k)=1]\\
=\sum_{j=1}^m[\gcd(j,k)=1]\sum_{i=1}^n[\gcd(i,j)=1]\\
=\sum_{j=1}^m[\gcd(j,k)=1]\sum_{i=1}^n\sum_{d|i\wedge d|j}\mu(d)\\
=\sum_{j=1}^m[\gcd(j,k)=1]\sum_{d|j}\mu(d)\lfloor\frac nd\rfloor\\
=\sum_{d=1}^n\mu(d)\lfloor \frac nd\rfloor\sum_{j=1}^{\lfloor\frac md\rfloor}[\gcd(jd,k)=1]\\
\sum_{d=1}^n\mu(d)[\gcd(d,k)=1]\lfloor \frac nd\rfloor\sum_{j=1}^{\lfloor\frac md\rfloor}[\gcd(j,k)=1]
\]

观察式子,后面那个部分很支持整除分块,所以往这方面考虑。

设\(f(n)=\sum_{i=1}^n[\gcd(i,k)=1]=\lfloor\frac nk \rfloor\varphi(k)+f(n \mod k)\)。可以\(O(k\log k)\)预处理\(f(1\sim k)\)。

  • 考虑分析式子

我们可以把\(k\)表示成\(p^aq\),假设\(p\)是\(k\)最小的质因子。对于1到\(k\)中每一个数可以预处理出他的\(p,q\)。设

\[g(n,k)=\sum_{d=1}^n\mu(d)[\gcd(d,k)=1]\\
=\sum_{d=2}^n\mu(d)[\gcd(d,p)=1][\gcd(d,q)=1]
\]

因为\(p\)是质数,所以\(\gcd(d,p)=1\)或\(p\)。考虑容斥,在满足 \(\gcd(d,q)=1\)的\(\mu(d)\)中减去也满足\((d,p)=p\)的。即

\[g(n,k)=\sum_{d=1}^n\mu(d)[\gcd(d,q)=1]-\sum_{d=1}^{\lfloor \frac np\rfloor}\mu(dp)[\gcd(d,q)=1]\\
=g(n,q)-\sum_{d=1}^{\lfloor \frac np\rfloor}\mu(dp)[\gcd(d,q)=1]
\]

当\(\gcd(d,p)\neq 1\)时\(\mu(dp)=0\),所以\(d\)要满足\((d,p)=1\)

\[g(n,k)=g(n,q)-\sum_{d=1}^{\lfloor \frac np\rfloor}\mu(dp)[\gcd(d,q)=1][\gcd(d,p)]=1
\]

因为\(\mu\)是积性函数,所以拆开得

\[g(n,k)=g(n,q)-\mu(p)\sum_{d=1}^{\lfloor\frac np\rfloor}\mu(d)[\gcd(d,k)=1]\\
=g(n,q)+g(\lfloor \frac np\rfloor,k)
\]

边界是\(g(0,k)=0\),以及\(g(n,1)=\sum_{d=1}^n\mu(d)\)直接杜教筛。

复杂度是 \(O\) (( \(k\) 的质因子个数) \(\sqrt n+n^{\frac{2}{3}}\) )

#include<bits/stdc++.h>
#define il inline
#define co const
template<class T>T read(){
T data=0,w=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar())if(ch=='-') w=-w;
for(;isdigit(ch);ch=getchar()) data=data*10+ch-'0';
return data*w;
}
template<class T>il T read(T&x) {return x=read<T>();}
typedef long long LL;
using namespace std; co int N=1e6+1,K=2001;
int n,m,k;
int pri[N],tot,mu[N];
int f[K],p[K],q[K];
int gcd(int a,int b){
return b==0?a:gcd(b,a%b);
}
void init(){
pri[1]=mu[1]=1;
for(int i=2;i<N;++i){
if(!pri[i]) pri[++tot]=i,mu[i]=-1;
for(int j=1;j<=tot&&i*pri[j]<N;++j){
pri[i*pri[j]]=1;
if(i%pri[j]==0){
mu[i*pri[j]]=0;
break;
}
mu[i*pri[j]]=-mu[i];
}
}
for(int i=2;i<N;++i) mu[i]+=mu[i-1];
for(int i=1;i<=k;++i) f[i]=f[i-1]+(gcd(i,k)==1);
// cerr<<"fk="<<f[k]<<endl;
for(int i=2;i<=k;++i){
for(int j=1;j<=tot;++j)
if(i%pri[j]==0) {p[i]=pri[j];break;}
for(q[i]=i/p[i];q[i]%p[i]==0;) q[i]/=p[i];
// if(k-i<=20) cerr<<i<<" p="<<p[i]<<" q="<<q[i]<<endl;
}
}
il int F(int n){
return n/k*f[k]+f[n%k];
}
typedef pair<int,int> pii;
map<pii,int> sg;
int G(int n,int k){
if(!n||n<N&&k==1) return mu[n];
if(sg.count(pii(n,k))) return sg[pii(n,k)];
if(k==1){
int ans=1;
for(int l=2,r;l<=n;l=r+1){
r=n/(n/l);
ans-=(r-l+1)*G(n/l,1);
}
return sg[pii(n,k)]=ans; // edit 1
}
return sg[pii(n,k)]=G(n,q[k])+G(n/p[k],k);
}
int main(){
read(n),read(m),read(k);
init();
// cerr<<"gnk="<<G(n,k)<<endl;
// cerr<<"fm="<<F(m)<<endl;
LL ans=0;
for(int l=1,r;l<=min(n,m);l=r+1){
r=min(n/(n/l),m/(m/l));
ans+=(LL)(G(r,k)-G(l-1,k))*(n/l)*F(m/l); // edit 2:(n/l)
}
printf("%lld\n",ans);
return 0;
}

这题我n/k忘带括号然后WA了。现在想想下取整除法只有分母具有结合律。

「NOI2016」循环之美的更多相关文章

  1. LibreOJ2085 - 「NOI2016」循环之美

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

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

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

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

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

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

  5. 「NOI2016」循环之美(小性质+min_25筛)

    传送门. 题解 感觉这题最难的是第一个结论. x/y首先要互质,然后如果在10进制是纯循环小数,不难想到y不是2.5的倍数就好了. 因为十进制下除以2和5是除得尽的. 必然会多出来的什么东西. 如果是 ...

  6. 【LOJ】#2085. 「NOI2016」循环之美

    题解 我们要求的其实是这个东西= = \(\sum_{i = 1}^{n}\sum_{j = 1}^{n}[(i,j) == 1][(j,k) == 1]\) 然后变一下形 \(\sum_{j = 1 ...

  7. 「NOI2016」优秀的拆分 解题报告

    「NOI2016」优秀的拆分 这不是个SAM题,只是个LCP题目 95分的Hash很简单,枚举每个点为开头和末尾的AA串个数,然后乘一下之类的. 考虑怎么快速求"每个点为开头和末尾的AA串个 ...

  8. 「NOI2016」网格 解题报告

    「NOI2016」网格 容易注意到,答案最多为2,也就是说答案为-\(1,0,1,2\)四种,考虑逐个判断. 无解的情况比较简单 如果\(nm\le c+1\),显然无解 如果\(nm=c+2\),判 ...

  9. 「NOI2016」区间 解题报告

    「NOI2016」区间 最近思维好僵硬啊... 一上来就觉得先把区间拆成两个端点进行差分,然后扫描位置序列,在每个位置维护答案,用数据结构维护当前位置的区间序列,但是不会维护. 于是想研究性质,想到为 ...

随机推荐

  1. Influx Sql系列教程一:database 数据库

    对于influxdb而言,database和我们更熟悉的mysql中的dababse没有什么特别的区别,可以将数据库简单理解为一堆表(measurement)的集合,接下来我们将看一下在influxd ...

  2. 值类型前加ref和out的区别

    1.值类型前加ref,在调用前必须先初始化,初始化之后在方法内部直接使用 值类型x前加了ref,方法外的x会随着方法内的x改变而改变,因为此时传的是地址,如下面的例子, x前加了ref所以x = x+ ...

  3. Visual Studio特性学习

    官方档案: https://docs.microsoft.com/en-us/visualstudio/get-started/visual-studio-ide?view=vs-2019

  4. QML CheckBox的使用

    "人类的全部历史都告诫有智慧的人,不要笃信时运,而应坚信思想. -- 爱献生" 这个在QT creator 帮助文档中非常容易查到. Import Statement: impor ...

  5. LeetCode 103. 二叉树的锯齿形层次遍历(Binary Tree Zigzag Level Order Traversal)

    103. 二叉树的锯齿形层次遍历 103. Binary Tree Zigzag Level Order Traversal 题目描述 给定一个二叉树,返回其节点值的锯齿形层次遍历.(即先从左往右,再 ...

  6. ubuntu18.04LTS服务器安装matlab4a

    下载matlab安装文件共包含三个文件:MATHWORKS_R2014A.part1.rar, MATHWORKS_R2014A.part2.rar, 相关文件(Crack)解压:$sudo apt ...

  7. Centos7 在线安装开发环境 jdk1.8+mysql+tomcat

    写在最前 刚刚开始接触Linux,并折腾着在服务器上部署自己的项目,当然作为一个后端开发人员,必不可少的东西肯定是 JDK Mysql Tomcat容器 每天记录一天,每天进步一点点~~ 1.更新系统 ...

  8. centos 7 安装nginx并启动(笔记)

    参考 https://www.cnblogs.com/liujuncm5/p/6713784.html Nginx 是 C语言 开发 一. gcc 安装安装 nginx 需要先将官网下载的源码进行编译 ...

  9. bootstrap 模态

    <script type="text/javascript" src="js/jquery-ui-custom.min.js"></scrip ...

  10. 【洛谷 P4070】 [SDOI2016]生成魔咒(后缀自动机)

    题目链接 建出\(SAM\)后,不同子串个数就是\(\sum len(i)-len(fa(i))\) 因为\(SAM\)在线的,所以每加入一个字符就能直接加上其贡献,于是这道题就没了. 因为\(x\) ...