Description

牛牛是一个热爱算法设计的高中生。在他设计的算法中,常常会使用带小数的数进行计算。牛牛认为,如果在k进制下,一个数的小数部分是纯循环的,那么它就是美的。现在,牛牛想知道:对于已知的十进制数n和m,在k进制下,有多少个数值上互不相等的纯循环小数,可以用分数 xy 表示,其中 1≤x≤n,1≤y≤m,且 x,y是整数。一个数是纯循环的,当且仅当其可以写成以下形式:a.c1˙c2c3…cp-1cp˙其中,a 是一个整数,p≥1;对于 1≤i≤p,ci是 kk 进制下的一位数字。例如,在十进制下,0.45454545……=0.4˙5˙是纯循环的,它可以用 5/11、10/22 等分数表示;在十进制下,0.1666666……=0.16˙则不是纯循环的,它可以用 1/6 等分数表示。需要特别注意的是,我们认为一个整数是纯循环的,因为它的小数部分可以表示成 0 的循环或是 k?1 的循环;而一个小数部分非 0 的有限小数不是纯循环的。

Input

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

Output

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

Sample Input

2 6 10

Sample Output

4
explanation
满足条件的数分别是:
1/1=1.0000……
1/3=0.3333……
2/1=2.0000……
2/3=0.6666……
1/1 和 2/2 虽然都是纯循环小数,但因为它们相等,因此只计数一次;同样,1/3 和 2/6 也只计数一次。

正解:莫比乌斯函数+杜教筛。

首先,小学奥数学过一个东西。一个分数是纯循坏小数,当且仅当这个分数的分母没有2或5作为因子,而10分解以后正好是2和5。那么我们类比一下:k进制分数是纯循环小数是不是就是分母没有k的因数。也就是说,k和分母要互质。

所以我们要求的就是:$Ans=\sum_{i=1}^{n}\sum_{j=1}^{m}[\gcd(i,j)==1,\gcd(j,k)==1]$

然后一脸懵逼,果断24分暴力。(套路用不上了。。)

24分暴力:

 //It is made by wfj_2048~
#include <algorithm>
#include <iostream>
#include <complex>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#define inf (1<<30)
#define il inline
#define RG register
#define ll long long using namespace std; int n,m,k,ans; il int gi(){
RG int x=,q=; RG char ch=getchar(); while ((ch<'' || ch>'') && ch!='-') ch=getchar();
if (ch=='-') q=-,ch=getchar(); while (ch>='' && ch<='') x=x*+ch-,ch=getchar(); return q*x;
} il int gcd(RG int a,RG int b){ return b ? gcd(b,a%b) : a; } il void work(){
n=gi(),m=gi(),k=gi();
for (RG int i=;i<=m;++i){
if (gcd(i,k)!=) continue;
for (RG int j=;j<=n;++j) if (gcd(i,j)==) ans++;
}
printf("%d\n",ans); return;
} int main(){
work();
return ;
}

其实上式是可以化简的,我们考虑如何化简这个式子。

$Ans=\sum_{i=1}^{m}[\gcd(i,k)==1]\sum_{j=1}^{n}[\gcd(i,j)==1]$

$Ans=\sum_{i=1}^{m}[gcd(i,k)==1]\sum_{j=1}^{n}\sum_{d|i,d|j}\mu(d)$

$Ans=\sum_{i=1}^{m}[\gcd(i,k)==1]\sum_{d|i}^{n}\mu(d)\left \lfloor \frac{n}{d} \right \rfloor$

其实到这里,就是莫比乌斯函数的24分暴力了。。但这不是跟$O(n^{2})$暴力一样的分吗。。

我们把$\mu$提前枚举,那么$Ans=\sum_{d=1}^{min(n,m)} \mu(d)\left \lfloor \frac{n}{d} \right \rfloor \sum_{i=1}^{m} [d|i,\gcd(i,k)==1]$

$Ans=\sum_{d=1}^{min(n,m)} \mu(d)\left \lfloor \frac{n}{d} \right \rfloor \sum_{i=1}^{\frac{m}{d}} [\gcd(i*d,k)==1]$

$Ans=\sum_{d=1}^{min(n,m)} [\gcd(d,k)==1]\mu(d)\left \lfloor \frac{n}{d} \right \rfloor \sum_{i=1}^{\frac{m}{d}} [\gcd(i,k)==1]$

我们设$f(n)=\sum_{i=1}^{n}[\gcd(i,k)==1]$。根据欧几里得定理,$f(n)=\left \lfloor \frac{n}{k} \right \rfloor f(k)+f(n \bmod k)$

于是我们预处理出$f$在$[1,k]$的取值,就能把复杂度降到$O(nlogn)$,实际上可以过84分,相当于$O(n)$的复杂度。

84分暴力:

 //It is made by wfj_2048~
#include <algorithm>
#include <iostream>
#include <complex>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#define inf (1<<30)
#define N (20000010)
#define il inline
#define RG register
#define ll long long using namespace std; int f[],vis[N],mu[N],prime[N],n,m,k,nn,cnt;
ll ans; il int gi(){
RG int x=,q=; RG char ch=getchar(); while ((ch<'' || ch>'') && ch!='-') ch=getchar();
if (ch=='-') q=-,ch=getchar(); while (ch>='' && ch<='') x=x*+ch-,ch=getchar(); return q*x;
} il int gcd(RG int a,RG int b){ return b ? gcd(b,a%b) : a; } il void pre(){
vis[]=mu[]=;
for (RG int i=;i<=nn;++i){
if (!vis[i]) mu[i]=-,prime[++cnt]=i;
for (RG int j=,k=i*prime[j];j<=cnt && k<=nn;++j,k=i*prime[j]){
vis[k]=; if (i%prime[j]) mu[k]=-mu[i]; else break;
}
}
for (RG int i=;i<=k;++i) f[i]=f[i-]+(gcd(i,k)==); return;
} il void work(){
n=gi(),m=gi(),k=gi(),nn=min(n,m); pre();
for (RG int d=;d<=nn;++d){
if (gcd(d,k)!=) continue;
ans+=(ll)mu[d]*(ll)(n/d)*(ll)((ll)(m/d/k)*(ll)f[k]+(ll)f[m/d%k]);
}
printf("%lld\n",ans); return;
} int main(){
work();
return ;
}

100分:

自己写不动了。。LCF学长的题解写得挺好的:http://www.cnblogs.com/lcf-2000/p/6250330.html

摘自学长博客:

我们考虑接下来该如何优化。由于$\lfloor \frac{m}{x} \rfloor$只有$\sqrt{m}$种取值,$\lfloor \frac{n}{x} \rfloor$只有$\sqrt{n}$种取值,于是我们显然可以分段求和。然后,我们就需要快速求出$\sum_{i=1}^n[i\perp k]\mu(i)$的值。

不妨设$g(n,k)=\sum_{i=1}^n[i\perp k]\mu(i)$,我们来考虑一下这个函数如何快速求。我们先考虑$k$的一个质因数$p$,那么$k$显然可以写成$p^cq$的形式。由于在$[1,n]$的范围中只有与$k$互质的才是有效值,那么若$x\perp k$,我们可以得到$x\perp p$并且$x\perp q$。于是,我们可以考虑从$x\perp q$的取值中减去$x$不与$p$互质的部分,就可以得到$x\perp k$的部分。这里如果不懂的话可以自己画一个$x\perp q$,$x\perp p$,$x\perp k$的关系图理解一下。

由于所有与$q$互质的数一定可以写成$p^xy(y\perp q)$的形式。那么我们需要减去的数一定满足$x>0$。又由于当$x>1$时$\mu(p^xy)=0$,所以我们只需要考虑$x=1$的情况即可。在这种情况下,我们需要考虑的数就是$py(y\perp q)$的形式,所以我们可以得到如下式子:\begin{aligned}  g(n,k)&=\sum_{i=1}^n[i\perp q]\mu(i)-\sum_{y=1}^{\lfloor\frac{n}{p}\rfloor}[py\perp q]\mu(py) \\&=g(n,q)- \sum_{y=1}^{\lfloor\frac{n}{p}\rfloor}[y\perp q]\mu(py)\end{aligned}

上面的最后一步是由于$p\perp q$,所以$py\perp q$只需在保证$y\perp q$即可。

我们接着来考虑后一个式子。显然当$p\perp y$的时候$\mu(py)=\mu(p)\mu(y)$,否则$\mu(py)=0$。于是,我们又得到了:

\begin{aligned} g(n,k)&=g(n,q)- \sum_{y=1}^{\lfloor\frac{n}{p}\rfloor}[y\perp p][y\perp q]\mu(p)\mu(y)\\&=g(n,q)-\mu(p)\sum_{y=1}^{\lfloor\frac{n}{p}\rfloor}[y\perp k]\mu(y)\\&=g(n,q)+g(\lfloor\frac{n}{p}\rfloor,k) \end{aligned}

于是我们就可以递归求解了。容易发现边界情况就是$n=0$或者$k=1$。$n=0$的时候直接返回$0$就可以了,$k=1$的时候就是莫比乌斯函数的前缀和,用杜教筛求出来就可以了。由于每次递归要么$n$会变成$\lfloor \frac{n}{p} \rfloor$,有$O(\sqrt{n})$种取值;要么$p$少了一个质因数,有$\omega(k)$种取值,所以总共有$O(\omega(k)\sqrt{n})$种取值,记忆化搜索即可。其中$\omega(k)$表示$k$的不同的质因子数目。于是最后的总复杂度为$O(\omega(k)\sqrt{n}+n^{\frac{2}{3}})$,可以通过此题。

我也不写哈希了,直接强行$map$就好。。

 //It is made by wfj_2048~
#include <algorithm>
#include <iostream>
#include <complex>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#define inf (1<<30)
#define N (5000010)
#define il inline
#define RG register
#define ll long long
#define calc(x) ( (x/k)*f[k]+f[x%k] ) using namespace std; map <ll,map<ll,ll> >gg;
map <ll,ll> ff; ll f[],di[],vis[N],mu[N],prime[N],n,m,k,nn,NN,pos,cnt,kcnt,ans; il ll gi(){
RG ll x=,q=; RG char ch=getchar(); while ((ch<'' || ch>'') && ch!='-') ch=getchar();
if (ch=='-') q=-,ch=getchar(); while (ch>='' && ch<='') x=x*+ch-,ch=getchar(); return q*x;
} il ll gcd(RG ll a,RG ll b){ return b ? gcd(b,a%b) : a; } il void pre(){
vis[]=mu[]=; RG ll kk=k;
for (RG ll i=;i<=nn;++i){
if (!vis[i]) mu[i]=-,prime[++cnt]=i;
for (RG ll j=,k=i*prime[j];j<=cnt && k<=nn;++j,k=i*prime[j]){
vis[k]=; if (i%prime[j]) mu[k]=-mu[i]; else break;
}
}
for (RG ll i=;i<=k;++i){
if (!(kk%i)) di[++kcnt]=i;
while (!(kk%i)) kk/=i;
}
for (RG ll i=;i<=k;++i) f[i]=f[i-]+(gcd(i,k)==);
for (RG ll i=;i<=nn;++i) mu[i]+=mu[i-]; return;
} il ll du(RG ll x){
if (x<=nn) return mu[x];
if (ff[x]) return ff[x];
RG ll ans=,pos;
for (RG ll i=;i<=x;i=pos+)
pos=x/(x/i),ans-=(pos-i+)*du(x/i);
return ff[x]=ans;
} il ll g(RG ll x,RG ll y){
if (x<=) return x;
if (!y) return du(x);
if (gg[x][y]) return gg[x][y];
return gg[x][y]=g(x,y-)+g(x/di[y],y);
} il void work(){
n=gi(),m=gi(),k=gi(); NN=min(n,m);
nn=min(NN,5000000LL); pre();
for (RG ll d=;d<=NN;d=pos+){
pos=min(n/(n/d),m/(m/d));
ans+=(g(pos,kcnt)-g(d-,kcnt))*(ll)(n/d)*(ll)calc(m/d);
}
printf("%lld\n",ans); return;
} int main(){
work();
return ;
}

bzoj4652 [Noi2016]循环之美的更多相关文章

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

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

  2. BZOJ4652: [Noi2016]循环之美(莫比乌斯反演,杜教筛)

    Description 牛牛是一个热爱算法设计的高中生.在他设计的算法中,常常会使用带小数的数进行计算.牛牛认为,如果在 k  进制下,一个数的小数部分是纯循环的,那么它就是美的.现在,牛牛想知道:对 ...

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

    因为要求数值不同,不妨设gcd(x,y)=1.由提示可以知道,x/y是纯循环小数的充要条件是x·klen=x(mod y).因为x和y互质,两边同除x,得klen=1(mod y).那么当且仅当k和y ...

  4. BZOJ4652 [Noi2016]循环之美 【数论 + 莫比乌斯反演 + 杜教筛】

    题目链接 BZOJ 题解 orz 此题太优美了 我们令\(\frac{x}{y}\)为最简分数,则\(x \perp y\)即,\(gcd(x,y) = 1\) 先不管\(k\)进制,我们知道\(10 ...

  5. luogu 1587 [NOI2016]循环之美

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

  6. 并不对劲的bzoj4652:loj2085:uoj221:p1587:[NOI2016]循环之美

    题目大意 对于已知的十进制数\(n\)和\(m\),在\(k\)进制下,有多少个数值上互不相等的纯循环小数,可以用\(x/y\)表示,其中 \(1\leq x\leq n,1\leq y\leq m\ ...

  7. [NOI2016]循环之美

    Description 牛牛是一个热爱算法设计的高中生.在他设计的算法中,常常会使用带小数的数进行计算.牛牛认为,如果在 k  进制下,一个数的小数部分是纯循环的,那么它就是美的.现在,牛牛想知道:对 ...

  8. [NOI2016]循环之美(杜教筛)

    首先要求每个数互不相等,故有$x\perp y$. 可以发现$\frac{x}{y}$在$k$进制下为纯循环小数的充要条件为$x\cdot k^{len}\equiv x(mod\ y)$,即$y\p ...

  9. luogu P1587 [NOI2016]循环之美

    传送门 首先要知道什么样的数才是"纯循环数".打表可以发现,这样的数当且仅当分母和\(k\)互质,这是因为,首先考虑除法过程,每次先给当前余数\(*k\),然后对分母做带余除法,那 ...

随机推荐

  1. mysql 索引篇

    一.索引优化   索引优化主要还是依赖explain命令,关于explain命令相信大家并不陌生,具体用法和字段含义可以参考官网explain-output,这里需要强调rows是核心指标,绝大部分r ...

  2. DataTable的AcceptChanges()方法和DataRow的RowState属性

    这个属性是一个只读属性的枚举类型,一共有五个值,Detached,Unchanged,Added,Deleteed,Modified, 属性名 值 备注 Detached 1 已创建该行,但是该行不属 ...

  3. SharePoint 切换用户的小技巧

    前言 从SharePoint 2013开始,SharePoint就已经去掉了”Sign in as Different User”这个功能,也就是无法切换用户登录.当然,后来我们通过修改CONTROL ...

  4. redux核心思路和代码解析

    最近在公司内部培训的时候,发现很多小伙伴只是会用redux.react-redux.redux-thunk的api,对于其中的实现原理和数据真正的流向不是特别的清楚,知其然,也要知其所以然,其实red ...

  5. Linux之tr命令

    tr - translate or delete characters 删除或替换文字信息 参数: -d  删除字符串 -s  删除重复的字符串只保留一个 [root@BASE ~]# cat c.t ...

  6. ASP.NET Core:CMD命令行+记事本 创建Console程序和Web Application

    今天看了Scott关于ASP.NET Core的介绍视频,发现用命令行一步一步新建项目.添加Package.Restore.Build.Run 执行的实现方式,更让容易让我们了解.NET Core的运 ...

  7. cookie设置今日不提醒功能

    需求:为了实现 退出页面时 [启动今日不提醒]的功能.采用纯js.cookie来实现. /****今日不提醒 start *****/ var userid = <%=UserId %>; ...

  8. 【Java 并发】详解 ThreadLocal

    前言 ThreadLocal 主要用来提供线程局部变量,也就是变量只对当前线程可见,本文主要记录一下对于 ThreadLocal 的理解.更多关于 Java 多线程的文章可以转到 这里. 线程局部变量 ...

  9. 急速搭建SuperMap iCloudManager for Docker环境

    大家好,SuperMap iCloudManager 是超图的 GIS 云管理系统,它是出色的云GIS平台的大管家. 它很简单,部署操作都很简单. 它很智能,可以实时监控 GIS 业务环境的 CPU ...

  10. 老李分享:性能测试你不应该只知道loadrunner(1)

    老李分享:性能测试你不应该只知道loadrunner(1)   poptest是国内唯一一家培养测试开发工程师的培训机构,以学员能胜任自动化测试,性能测试,测试工具开发等工作为目标.poptest测试 ...