bzoj4652 [Noi2016]循环之美
Description
Input
Output
Sample Input
Sample Output
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]循环之美的更多相关文章
- [UOJ#221][BZOJ4652][Noi2016]循环之美
[UOJ#221][BZOJ4652][Noi2016]循环之美 试题描述 牛牛是一个热爱算法设计的高中生.在他设计的算法中,常常会使用带小数的数进行计算.牛牛认为,如果在 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进制下是一个纯循环的. 由于数值相同的 ...
- 并不对劲的bzoj4652:loj2085:uoj221:p1587:[NOI2016]循环之美
题目大意 对于已知的十进制数\(n\)和\(m\),在\(k\)进制下,有多少个数值上互不相等的纯循环小数,可以用\(x/y\)表示,其中 \(1\leq x\leq n,1\leq y\leq m\ ...
- [NOI2016]循环之美
Description 牛牛是一个热爱算法设计的高中生.在他设计的算法中,常常会使用带小数的数进行计算.牛牛认为,如果在 k 进制下,一个数的小数部分是纯循环的,那么它就是美的.现在,牛牛想知道:对 ...
- [NOI2016]循环之美(杜教筛)
首先要求每个数互不相等,故有$x\perp y$. 可以发现$\frac{x}{y}$在$k$进制下为纯循环小数的充要条件为$x\cdot k^{len}\equiv x(mod\ y)$,即$y\p ...
- luogu P1587 [NOI2016]循环之美
传送门 首先要知道什么样的数才是"纯循环数".打表可以发现,这样的数当且仅当分母和\(k\)互质,这是因为,首先考虑除法过程,每次先给当前余数\(*k\),然后对分母做带余除法,那 ...
随机推荐
- tp框架之对列表的一系列操作及跳转页面(详细步骤)
依旧是在Main控制器里面写类方法,如果想看tp全部的话,可以从前几篇开始看,都是一整个步骤下来的 在控制器中重新写个类 然后再做个shouye.html页面 nation表的数据,将会在shou.h ...
- fopen中的mode(20161115)
mode mode 参数指定了所要求到该流的访问类型.可以是以下: fopen() 中 mode 的可能值列表 mode 说明 'r' 只读方式打开,将文件指针指向文件头. 'r+' 读写方式打开,将 ...
- Android学习探索之本地原生渲染 LaTeX数据公式
前言: 一直致力于为公司寻找更加高效的解决方案,作为一款K12在线教育App,功能中难免会有LaTeX数学公式的显示需求,这部分公司已经实现了此功能,只是个人觉得在体验和效率上还是不太好,今天来聊一下 ...
- ISO c++ 14 重点介绍[译]
原文链接 http://marknelson.us/2014/09/11/highlights-of-iso-c14/ 下面是对你的日常开发有重大影响的C++14新变动,列出了一些示例代码,并讨论何时 ...
- NOI全国赛(1998)——围巾裁剪
裁缝有一块非常珍贵的丝绸围巾.可惜的是,围巾的某些部分已经被蛀虫给咬坏了.裁缝当然不愿意就这么把围巾给丢了,于是,他想把围巾给裁成两块小围巾送给他的两个女儿.自然,两块小围巾的面积之和越大越好. 这 ...
- WPF实用小工具
Kaxaml 一款轻量级的Xaml代码编辑器,提供了可视的效果可以看到修改代码后的实时效果图.个人习惯于用它测试系统默认控件的行为和布局,小片段的xaml也可以拿到这个工具上测试效果.这款工具还提供了 ...
- windows 安装Beautiful Soup(转)
Beautiful Soup是一个Python的一个库,主要为一些短周期项目比如屏幕抓取而设计.有三个特性使得它非常强大: 1.Beautiful Soup提供了一些简单的方法和Python术语,用于 ...
- 大数据学习记录之ssh绵密登录
1,在服务器端 ssh-keygen 2,使用ssh-copy-id 192.168.2.146 3,再测试一下ssh 192.168.2.146 exit 退出当前登录 具体流程为:A,B两台机器 ...
- 关于SQL的一些小知识
在代码中调用存储过程的时,必须先测试存储过程,存储过程测试成功之后再去java中去调用!!@!@#!@!@! 以后自己写的存储过程写一个本地保存一个.!~~~!!(这个很关键) 以后在代码中的SQL都 ...
- linux ssh -l 命令运用
ssh是远程登录命令,-l选项是最常用的选项,下面是我的一些总结 远程登录:ssh -l userName ip # 远程登录到 10.175.23.9 ssh -l root2 10.175. ...