luogu P1587 [NOI2016] 循环之美
首先我们从简单的十进制入手,我们发现如果除数和被除数互质,且除数为\(2\)或\(5\)的倍数,那么一定不是循环小数,反之则能进入循环。
推广一下,如果除数和\(k\)互质,那么就是纯循环小数,否则不是纯循环小数。
因此我们就是要求这个式子:
\(\sum\limits_{i=1}^{n}{\sum\limits_{j=1}^{m}{[\gcd(i,j)==1][\gcd(K,j)==1]}}\)
把后面那个\(\gcd\)反演掉得到
\(\sum\limits_{k|K}{\mu(k)\sum\limits_{i=1}^{n}{\sum\limits_{j=1}^{\frac{m}{k}}{[\gcd(i,j)==1][\gcd(i,k)==1]}}}\)
若\(k=1\),\(\sum\limits_{i=1}^{n}{\sum\limits_{j=1}^{m}{[gcd(i,j)==1]}}\)
\(=\sum\limits_{i=1}^{n}{\mu(i)\frac{n}{i}\frac{m}{i}}\)
可以发现是经典整除分块,杜教筛即可。
若\(k\not =1\),则\(n,m\)必定有一个减半,状态数是\(O(k\log^2n)\)的。
因此可以在\(O(k\log ^2n+n^{\frac{3}{4}})\)内处理。
code:
#include<bits/stdc++.h>
#define Gc() getchar()
#define Me(x,y) memset(x,y,sizeof(x))
#define Mc(x,y) memcpy(x,y,sizeof(x))
#define d(x,y) ((m)*(x-1)+(y))
#define R(n) (rnd()%(n)+1)
#define Pc(x) putchar(x)
#define LB lower_bound
#define UB upper_bound
#define PB push_back
using ll=long long;using db=double;using lb=long db;using ui=unsigned;using ull=unsigned ll;
using namespace std;const int N=1e7+5,M=1e7,K=2e3+5,mod=1e9+7,Mod=mod-1;const db eps=1e-5;const int INF=1e9+7;
int n,m,k,x,y,z,mu[N],pr[N],ph,Fl[N],Q[N];ll Ans;vector<int> S[N];
namespace QM{
unordered_map<int,int> f;int calc(int x){
if(x<=M) return Q[x];if(!x) return 0;if(f.count(x)) return f[x];ll Ans=1;
int i,j;for(i=2;i<=x;i=j+1) j=x/(x/i),Ans-=calc(x/i)*(j-i+1);return f[x]=Ans;
}
}
ll calc(int n,int m,int k){
if(!n||!m) return 0;ll Ans=0;for(int i:S[k])mu[i]&&(Ans+=mu[i]*calc(m/i,n,i));
int i,j;for(i=1;i<=min(n,m);i=j+1) j=min(n/(n/i),m/(m/i)),Ans+=1ll*(QM::calc(j)-QM::calc(i-1))*(n/i)*(m/i);return Ans;
}
int main(){
freopen("1.in","r",stdin);
int i,j,h;scanf("%d%d%d",&n,&m,&k);mu[1]=1;for(i=2;i<=k;i++) for(j=i;j<=k;j+=i) S[j].PB(i);
for(i=2;i<=M;i++){
!Fl[i]&&(pr[++ph]=i,mu[i]=-1);for(j=1;j<=ph&&i*pr[j]<=M;j++) {Fl[i*pr[j]]=2;if(i%pr[j]==0) break;mu[i*pr[j]]=-mu[i];}
}for(i=1;i<=M;i++) Q[i]=Q[i-1]+mu[i];
/*for(i=1;i<=min(n,m);i++){
for(j=i;j<=m;j+=i) if(__gcd(k,j)==1) Ans+=mu[i]*(n/i);
}*/printf("%lld\n",calc(n,m,k));
}