2005: [Noi2010]能量采集
题意:有一二维平面n*m,从(0,0)开始看,到每个点的贡献为(gcd(i,j)-1)*2+1,求总贡献;
思路:枚举gcd,二维平面优化复杂度O(sqrt(n)+sqrt(m));
if(n>m) swap(n,m)
![This is the rendered form of the equation. You can not edit this directly. Right click will give you the option to save the image, and in most browsers you can drag the image onto your desktop or another program.](https://i-blog.csdnimg.cn/blog_migrate/2fb6c0521f76cea2450102ad58492fa7.gif)
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define mod 1000000007
#define ll long long
const int N=300100;
bool check[N+10];
int prime[N+10];
int mu[N+10];
void Moblus()
{
memset(check,false,sizeof(check));
mu[1]=1;
int tot=0;
for(int i=2; i<=N; i++)
{
if(!check[i])
{
prime[tot++]=i;
mu[i]=-1;
}
for(int j=0; j<tot; j++)
{
if(i*prime[j]>N) break;
check[i*prime[j]]=true;
if(i%prime[j]==0)
{
mu[i*prime[j]]=0;
break;
}
else
{
mu[i*prime[j]]=-mu[i];
}
}
}
}
int sum[N+10];
ll solve(int n,int m)
{
ll ans=0;
for(int i=1,la=0;i<=n;i=la+1)
{
la=min(n/(n/i),m/(m/i));
ans+=(ll)(sum[la]-sum[i-1])*(n/i)*(m/i);
}
return ans;
}
int main()
{
Moblus();
sum[0]=0;
for(int i=1;i<=N;i++)
sum[i]=sum[i-1]+mu[i];
int n,m;
while(~scanf("%d%d",&n,&m))
{
if(n>m) swap(n,m);
ll ans=0;
for(int i=1;i<=n;i++)
{
int n1=n/i,m1=m/i;
ll an=solve(n1,m1);
ans+=an*((i-1)*2+1);
}
printf("%lld\n",ans);
}
return 0;
}
题意:给定整数N,求1<=x,y<=N 且Gcd(x,y) 为素数的数对(x,y)有多少对?
思路:枚举素数,和上题一样
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define mod 1000000007
#define ll long long
const int N=10000010;
bool check[N+10];
int prime[N+10];
int mu[N+10];
int tot=0;
void Moblus()
{
memset(check,false,sizeof(check));
mu[1]=1,tot=0;
for(int i=2; i<=N; i++)
{
if(!check[i])
{
prime[tot++]=i;
mu[i]=-1;
}
for(int j=0; j<tot; j++)
{
if(i*prime[j]>N) break;
check[i*prime[j]]=true;
if(i%prime[j]==0)
{
mu[i*prime[j]]=0;
break;
}
else
{
mu[i*prime[j]]=-mu[i];
}
}
}
}
int sum[N+10];
ll solve(int n,int m)
{
ll ans=0;
for(int i=1,la=0; i<=n; i=la+1)
{
la=min(n/(n/i),m/(m/i));
ans+=(ll)(sum[la]-sum[i-1])*(n/i)*(m/i);
}
return ans;
}
int main()
{
Moblus();
// printf("%d\n",tot);
sum[0]=0;
for(int i=1; i<=N; i++)
sum[i]=sum[i-1]+mu[i];
int n,m;
while(~scanf("%d",&n))
{
m=n;
ll ans=0;
for(int i=0; i<tot; i++)
{
int n1=n/prime[i],m1=m/prime[i];
ll an=solve(n1,m1);
ans+=an;
}
printf("%lld\n",ans);
}
return 0;
}
SQFREE - Square-free integers
题意:Square-free integer:无平方因子数。输入n,求1~n的无平方因子数个数;
思路:容斥+莫比乌斯函数;
当然容斥公式是别人的:
[1,x] 之间的无平方因子数个数:
对于sqrt(x) 以内所有的质数,
有x以内的无平方因子数=0个质数乘积的平方的倍数的数的数量(1的倍数)
- 每个质数的平方的倍数的数的数量(4的倍数,9的倍数,25的倍数...)
+ 每2个质数乘积的平方的倍数的数的数量(36的倍数,100的倍数...)
........
公式:
参考blog:
点击打开链接
代码:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
#define mod 1000000007
#define ll long long
const int N=10000010;
bool check[N+10];
int prime[N+10];
int mu[N+10];
int tot=0;
void Moblus()
{
memset(check,false,sizeof(check));
mu[1]=1,tot=0;
for(int i=2; i<=N; i++)
{
if(!check[i])
{
prime[tot++]=i;
mu[i]=-1;
}
for(int j=0; j<tot; j++)
{
if(i*prime[j]>N) break;
check[i*prime[j]]=true;
if(i%prime[j]==0)
{
mu[i*prime[j]]=0;
break;
}
else
{
mu[i*prime[j]]=-mu[i];
}
}
}
}
int main()
{
Moblus();
int t;
scanf("%d",&t);
while(t--)
{
ll n;
scanf("%lld",&n);
ll x=sqrt(n);
ll ans=0;
for(ll i=1; i<=x;i++)
{
ans+=mu[i]*(n/i/i);
}
printf("%lld\n",ans);
}
return 0;
}
2440: [中山市选2011]完全平方数
题意:求第k个无平方因子数;
思路:二分答案,然后用上题作为判断条件;
代码:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
#define mod 1000000007
#define ll long long
const int N=100010;
bool check[N+10];
int prime[N+10];
int mu[N+10];
int tot=0;
void Moblus()
{
memset(check,false,sizeof(check));
mu[1]=1,tot=0;
for(int i=2; i<=N; i++)
{
if(!check[i])
{
prime[tot++]=i;
mu[i]=-1;
}
for(int j=0; j<tot; j++)
{
if(i*prime[j]>N) break;
check[i*prime[j]]=true;
if(i%prime[j]==0)
{
mu[i*prime[j]]=0;
break;
}
else
{
mu[i*prime[j]]=-mu[i];
}
}
}
}
ll solve(ll x,ll n)
{
ll ans=0;
for(ll i=1; i<=x; i++)
{
ans+=mu[i]*(n/i/i);
}
return ans;
}
int main()
{
Moblus();
int t;
scanf("%d",&t);
while(t--)
{
int k;
scanf("%d",&k);
ll l=1,r=10000000000;
// printf("%lld\n",mid);
while(l<r)
{
ll mid=(l+r)>>1;
if(solve(sqrt(mid),mid)<k)
l=mid+1;
else
r=mid;
// printf("%lld %lld\n",l,r);
}
printf("%lld\n",l);
}
return 0;
}