Description

Link

求给定的 n 行 m 列的矩阵中,从(0,0)可以看到的点的数量。
其中 \(1\leq n,m\leq10^5\)


Solution

如果一个点 (x,y) , x 与 y 不互质,设 \(\gcd(x,y)=z\),则 (x/z,y/z) 一定会挡住 (0,0) 的视线。
(两点在同一直线上)
则题目转化为:求 \(\operatorname{[1,n]}\) 中每个数与 \(\operatorname{[1,m]}\) 中的数互质的个数的和。
做法可以参考:HDU 4135
总时间复杂度:\(\omicron(T\sqrt n)\)
Code:

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int MAXN=1e6;
#define int long long
int t,a,b,n,cnt,k,mp[MAXN+5],p[MAXN+5],ans[MAXN+5],num[MAXN+5],phi[MAXN+5],sum[MAXN+5],v[MAXN+5],tot,pp;
bool vis[MAXN+5];
void Work(int x)
{
	tot=0;
	for(int i=2;i*i<=x;i++)
	{
		if(x%i==0)
		{
			v[++tot]=i;
			while(x%i==0)
			{
				x/=i;
			}
		}
	}
	if(x!=1)
	{
		v[++tot]=x;
	}
}
void dfs(int now,int &V,int res,int up,int cc)
{
	if(now>tot)
	{
		if(!cc)
		{
			return;
		}
		if(cc&1)
		{
			V-=up/res;
		}
		else{
			V+=up/res;
		}
		return;
	}
	dfs(now+1,V,res*v[now],up,cc+1);
	dfs(now+1,V,res,up,cc);
}
int Ans(int x)
{
	if(!x)
	{
		return 0;
	}
	int val=x,cc=0;
	dfs(1,val,1,x,cc);
	return val;
}
signed main()
{
	scanf("%lld",&t);
	while(t--){
		int op=0;
		scanf("%lld%lld",&a,&b);
		for(int i=1;i<=b;i++)
		{
			Work(i);
			int tmp=Ans(a);
			op+=tmp;
		}
		printf("%lld\n",op);
	}
	return 0;
}

\(\Bbb{End.}\)
\(\Bbb{Thanks}\) \(\Bbb{For}\) \(\Bbb{Reading.}\)