題面
這題天秀
題意:求有多少個互質的x,y,x≤n,y≤m
使得 的小數在k進制下從第一位開始無限循環
我看到這題,突然發現和我小學5年級奧數學的內容很像(我小學好厲害)
當時講了怎麼把一個循環小數化成分數
從第一位開始循環的小數
循環節長度就是分母中9的個數
分子就是循環節
(證明就是等比數列求和,然後求極限,好像當時也講了)
比如
若不從第一位開始的就各種解方程的騷方法求出來
比如
(小學奧數普及)
推導到k進制
分母應該只能是若干個(k-1)
約分後也是若干個(k-1)的約數
就必定與k互質了
設
一輪畫柿子
k=1時爲杜教篩
然後玄學45000ms卡過bzoj
洛谷T兩個點
其實根據套路,玄學都要記憶化才能過
正解也是玄學
所以玄學的維數不要太多
有點T的玄學
#include <iostream>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <ctime>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <map>
using namespace std;
#define mmst(a, b) memset(a, b, sizeof(a))
#define mmcp(a, b) memcpy(a, b, sizeof(b))
typedef long long LL;
const int N=6006000;
LL n,m,k;
int miu[N],smiu[N];
int prime[N],num;
bool b[N];
map<int,LL> mp;
int gm(int x)
{
if(x<N)
return smiu[x];
if(mp.count(x))
return mp[x];
int res=1;
for(int i=2,last;i<=x;i=last+1)
{
last=x/(x/i);
res-=gm(x/i)*(last-i+1);
}
mp[x]=res;
return res;
}
LL G(int x,int y)
{
if(x>y)
swap(x,y);
LL res=0;
for(int i=1,last;i<=x;i=last+1)
{
last=min(x/(x/i),y/(y/i));
res+=(LL)(gm(last)-gm(i-1))*(LL)(x/i)*(y/i);
}
return res;
}
LL F(int x,int y,int d)
{
if(!x||!y)
return 0;
if(d==1)
return G(x,y);
LL res=0;
for(int i=1;i*i<=d;i++)
if(d%i==0)
{
res+=(LL)miu[i]*F(y/i,x,i);
if(i*i<d)
res+=(LL)miu[d/i]*F(y/(d/i),x,d/i);
}
return res;
}
int main()
{
miu[1]=1;
for(int i=2;i<N;i++)
{
if(!b[i])
prime[++num]=i,miu[i]=-1;
for(int j=1;j<=num&&i*prime[j]<N;j++)
{
miu[i*prime[j]]=-miu[i];
b[i*prime[j]]=1;
if(i%prime[j]==0)
{
miu[i*prime[j]]=0;
break;
}
}
}
for(int i=1;i<N;i++)
smiu[i]=smiu[i-1]+miu[i];
cin>>n>>m>>k;
cout<<F(n,m,k)<<endl;
return 0;
}
傳說中的正解
#include <iostream>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <ctime>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <map>
using namespace std;
#define mmst(a, b) memset(a, b, sizeof(a))
#define mmcp(a, b) memcpy(a, b, sizeof(b))
typedef long long LL;
const int N=6006000;
LL n,m,k,ans;
int u[N],miu[N],smiu[N],phi[N],f[N];
int prime[N],num;
bool b[N];
map<int,LL> mp;
map<LL,LL> mmp;
int gm(int x)
{
if(x<N)
return smiu[x];
if(mp.count(x))
return mp[x];
int res=1;
for(int i=2,last;i<=x;i=last+1)
{
last=x/(x/i);
res-=gm(x/i)*(last-i+1);
}
mp[x]=res;
return res;
}
int gcd(int x,int y)
{
if(!y)
return x;
return gcd(y,x%y);
}
int lj(int x)
{
return (x/k)*phi[k]+f[x%k];
}
LL F(int x,int y)
{
if(mmp.count(2001ll*x+y))
return mmp[2001ll*x+y];
if(!x)
return 0;
if(y==1)
return gm(x);
LL res=F(x,y/u[y])+F(x/u[y],y);
mmp[2001ll*x+y]=res;
return res;
}
int main()
{
phi[1]=miu[1]=1;
for(int i=2;i<N;i++)
{
if(!b[i])
prime[++num]=i,phi[i]=i-1,miu[i]=-1,u[i]=i;
for(int j=1;j<=num&&i*prime[j]<N;j++)
{
miu[i*prime[j]]=-miu[i];
b[i*prime[j]]=1;
u[i*prime[j]]=prime[j];
phi[i*prime[j]]=phi[i]*(prime[j]-1);
if(i%prime[j]==0)
{
phi[i*prime[j]]=phi[i]*prime[j];
miu[i*prime[j]]=0;
break;
}
}
}
for(int i=1;i<N;i++)
smiu[i]=smiu[i-1]+miu[i];
cin>>n>>m>>k;
int tu=1;
while(k>1)
{
tu*=u[k];
while(u[k/u[k]]==u[k])
k/=u[k];
k/=u[k];
}
k=tu;
for(int i=1;i<=k;i++)
if(gcd(i,k)==1)
f[i]++;
for(int i=1;i<=k;i++)
f[i]+=f[i-1];
for(int i=1,last;i<=min(n,m);i=last+1)
{
last=min(n/(n/i),m/(m/i));
ans+=(F(last,k)-F(i-1,k))*(LL)(n/i)*lj(m/i);
}
cout<<ans<<endl;
return 0;
}