萬惡之源--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;
}