Mophues HDU
Posted acmloser
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Mophues HDU相关的知识,希望对你有一定的参考价值。
原题链接
考察:莫比乌斯反演
菜狗不会啊QAQ
思路:
参考了大佬的题解,我们列出求答案的式子.
\\[\\sum_{k=1}^{min(n,m)}[f[k]<=p]\\sum_{i=1}^n\\sum_{j=1}^m[gcd(i,j)==k]
\\]
注意:f[k]为k的质因子个数.
\\[\\sum_{k=1}^{min(n,m)}[f[k]<=p]\\sum_{i=1}^{min(n/k,m/k)}mob[i]*\\frac{n}{i*k}*\\frac{m}{i*k}
\\]
这就是枚举\\(k\\),求\\(gcd(x,y)==k\\)的对数.直接这么算一定TLE.所以进一步化简式子.
令\\(T = i*k\\)
\\[\\sum_{k=1}^{min(n,m)}[f[k]<=p]\\sum_{T=1}^{min(n,m)}mob[T/k]*\\frac{n}{T}*\\frac{m}{T}
\\]
\\[\\sum_{T=1}^{min(n,m)}\\frac{n}{T}*\\frac{m}{T}\\sum_{k=1}^{T}[f[k]<=p]mob[T/k]
\\]
这就是枚举T,再枚举T的因数,如果满足\\(f[k]<=p\\),对于T 1~min(n,m) k 1~T 累加\\(mob\\)和
但是我们可以先枚举k,再枚举k的倍数,这样就可以优化时间复杂度.而且后半部分可以预处理,枚举k,T后,k的质因子个数也就确定了,那么我们可以求出\\(sum[T][f[k]]+=mob[T/k]\\)
最后把T,k累加即可.
Code
#include <iostream>
#include <cstring>
using namespace std;
typedef long long LL;
const int N = 500010,M=20;
int prime[N],cnt,mob[N],n,m,P,f[N],sum[N][M];
bool st[N];
void GetPrime(int n)
{
mob[1] = 1;
for(int i=2;i<=n;i++)
{
if(!st[i]) prime[++cnt] = i,mob[i] = -1;
for(int j=1;prime[j]<=n/i;j++)
{
st[i*prime[j]] = 1;
if(i%prime[j]==0)
{
mob[i*prime[j]] = 0;
break;
}
mob[i*prime[j]] = mob[i]*(-1);
}
}
}
void init(int n)
{
int t = n;
for(int i=1;prime[i]<=t/prime[i];i++)
{
if(t%prime[i]==0)
{
int s = 0;
while(t%prime[i]==0) t/=prime[i],s++;
f[n]+=s;
}
}
if(t>1) f[n]++;
}
int main()
{
int T;
scanf("%d",&T);
GetPrime(N-1);
for(int i=1;i<=N-10;i++) init(i);
for(int i=1;i<=N-10;i++)
for(int j=i;j<=N-10;j+=i)
sum[j][f[i]]+=mob[j/i];
for(int i=1;i<=N-10;i++)
for(int j=0;j<M;j++)//f[g]<=j的和
if(j) sum[i][j] += sum[i][j-1];//不能一起加,因为会重复.
for(int i=1;i<=N-10;i++)
for(int j=0;j<M;j++)//f[g]<=j的和
sum[i][j] += sum[i-1][j];
while(T--)
{
scanf("%d%d%d",&n,&m,&P);
if(P>=M) {printf("%lld\\n",(LL)n*m);continue;}
if(n>m) swap(n,m);
LL res = 0;
for(int i=1,r;i<=n;i=r+1)
{
r = min(n/(n/i),m/(m/i));
res+=(LL)(sum[r][P]-sum[i-1][P])*(n/i)*(m/i);
}
printf("%lld\\n",res);
}
return 0;
}
以上是关于Mophues HDU的主要内容,如果未能解决你的问题,请参考以下文章