万恶之源--bzoj2440 完全平方数 应该是这道题前身。
题意: 给n,k, 求
一.核心
莫比乌斯函数平方及以上因子=0,无平方因子(即素因子次数最大为1)=,如果都当成1来算,他们前缀和不正是:
等价于小于等于n,不含平方因子的个数和
二.化简证明:
第一种:容斥
莫比乌斯函数本质为容斥系数出发(不理解见链接)
求不含平方因子的个数和,容斥表达=1的平方的倍数的数(全部数)-2的平方的倍数的数-3的平方的倍数的数+6平方的的倍数的数(减2和3平方的倍数的时候减多了一部分,加回来)...数学上可以写成是,x就是容斥系数,刚好就是莫比乌斯函数。
因此
第二种:严谨证明
①第一个等号怎么来的?
②第二个等号:用d消去i,常见转换
(可能可行?)猜想--第三种:狄利克雷卷积构造g(x)套杜教筛
好像狄利克雷卷积只能结合一次...所以下面写法应该不对,先写出来吧。
三.代码
注意除了prime其他用long long
#include <bits/stdc++.h>
//#include<tr1/unordered_map>
using namespace std;
//using namespace std::tr1;//头文件和std都要加,c++11可用
typedef long long ll;
typedef unsigned long long ull;
const int N = 5e6+5;
ll mu[N],phi[N],mu2[N];//mu用来存前缀和
int prime[N];
int vis[N];
map<ll,ll>ansmu,ansphi,ansmu2;//数组不够大,额外开,需要map
//unorder_map比普通map少了排序,会快一些
inline int read() { //输入挂
ll X=0,w=1; char c=getchar();
while (c<'0'||c>'9') { if (c=='-') w=-1; c=getchar(); }
while (c>='0'&&c<='9') X=X*10+c-'0',c=getchar();
return X*w;
}
void init()
{
int cnt=0;
mu[1]=mu2[1]=1;
for(int i=2;i<=N;i++)//统一ll和int!!!
{
if(!vis[i])
{
prime[++cnt]=i;//++写在前面
mu[i]=-1;//素数 只有它本身一个素因子
mu2[i]=-1;
}
for(int j=1;prime[j]*i<=N&&j<=cnt;j++)//不越两界
{
vis[i*prime[j]]=1;
if(i%prime[j]==0)
{
//mu[i*prime[j]]=0;//初始化为0所以这项可有可无
break;
}
else
{
mu[i*prime[j]]=-mu[i];//多一个素因子变正负
mu2[i*prime[j]]=-mu2[i];
}
}
}
for(int i=1;i<=N;i++)mu[i]+=mu[i-1];//前缀和
}
ll S_mu(ll n)
{
if(n<N)return mu[n];//同上
if(ansmu[n])return ansmu[n];
ll ans=1;
for(ll l=2,r;l<=n;l=r+1)
r=n/(n/l) ,ans-=(r-l+1)*S_mu(n/l); //I*mu
return ansmu[n]=ans;
}
ll S_mu2(ll n)
{
ll t=sqrt(n);
ll ans=0;
for(ll i=1;i<=t;i++){
if(n/(i*i)==0)break;//不剪枝也不会TLE
ans+=mu2[i]*(n/(i*i));
}
return ans;
}
int main()
{
init();
int T=read();
ll n,k;
while(T--)
{
//ll n=read(); ll k=read();//如果用输入挂也要改ll
scanf("%lld %lld",&n,&k);
if(k==0) printf("%lld\n",n);
else if(k%2==1)printf("%lld\n",S_mu(n));
else printf("%lld\n",S_mu2(n));
}
return 0;
}