[Ybt Gold Medal Navigation 8-4-2] [luogu P2158] [POJ 3090] Visible Lattice Points/ Honor Guard/ Visible Lattice Points

Visible Lattice Points/ Honor Guard/ Visible Lattice Points

Topic link: ybt gold medal navigation 8-4-2 / luogu P2158 / POJ 3090

General idea

There is a grid, and then you can draw a line from (0,0) to other integer points, but you cannot pass through other integer points in the middle.

Ask how many lines you can draw.

Ideas

Insert picture description here
We consider to see if we can find anything based on this graph.

Then you will find that it has symmetry, that is, the line segment from the lower left to the upper right is the axis of symmetry, and the distribution and number of the line segments on both sides are symmetrical.
Then it also has a matching line on this line.

Then you can just ask for the number of one side, and then multiply by two and add one. That's the answer.

Then you think about how to do it on one side.
Then you think, if the line is not satisfied, what is it like.
It can be imagined that if a point (x, y) (x, y)(x,y ), 有gcd ⁡ (x, y) ≠ 1 \ gcd (x, y) \ neq1gcd(x,and )=1 , it must be at least a bit(x / gcd ⁡ (x, y), y / gcd ⁡ (x, y)) (x/\gcd(x,y),y/\gcd(x,y))(x/gcd(x,and ) ,and /gcd(x,y ) ) on the line that connects to it, it won’t work.

Then it becomes gcd ⁡ (x, y) = 1 \gcd(x,y)=1gcd(x,and )=1 .
Then you can enumeratexxx , then it becomes seeking1 ∼ x 1\sim x1x andxxThe number of x relatively primes.
That's Euler's function. There are a lot of things to do, and you can use a linear sieve to do it.

Code (ybt & luogu)

Tips

Here the size of the grid is nnn ( 0 , 0 ) ∼ ( n − 1 , n − 1 ) (0,0)\sim(n-1,n-1) (0,0)(n1,n1 ) .
It must be noted that it is not(n, n) (n, n)(n,n ) , it is less than rather than less than or equal to.

#include<cstdio>
#define ll long long

using namespace std;

int n, phi[40001], pr[40001];
bool np[40001];
ll ans;

int main() {
    
    
	scanf("%d", &n);
	
	phi[1] = 1;//求出 1~n 每个数的 phi 值
	for (int i = 2; i < n; i++) {
    
    
		if (!np[i]) {
    
    
			phi[i] = i - 1;
			pr[++pr[0]] = i;
			
		}
		for (int j = 1; j <= pr[0] && pr[j] * i < n; j++) {
    
    
			np[i * pr[j]] = 1;
			if (i % pr[j] == 0) phi[i * pr[j]] = phi[i] * pr[j];//不止一个这样的因子,只有第一个要减一
				else phi[i * pr[j]] = phi[i] * (pr[j] - 1);
			if (i % pr[j] == 0) break;//第一次出现,要减一
		}
	}
	
	for (int i = 1; i < n; i++)//对称性,乘二
		ans += 2ll * phi[i];
	ans++;//中间的那一条
	
	printf("%lld", ans);
	
	return 0;
}

Code (POJ)

Tips

This question has multiple sets of data, and it is (0, 0) ∼ (n, n) (0,0)\sim(n,n)(0,0)(n,n)

We can put φ \varphiThe φ function is preprocessed first, and then the prefix sum multiplied by two is preprocessed, and then you canO (1) O(1)O ( 1 ) The inquiry has been processed.

//由于思路相同,代码实现也差不多,就不再作注释了
#include<cstdio>
#define ll long long

using namespace std;

ll T, n, pr[40001];
bool np[40001];
ll phi[40001];

int main() {
    
    
	phi[1] = 1;
	for (ll i = 2; i <= 40000; i++) {
    
    
		if (!np[i]) {
    
    
			phi[i] = i - 1;
			pr[++pr[0]] = i;
		}
		for (ll j = 1; j <= pr[0] && pr[j] * i < 40000; j++) {
    
    
			np[i * pr[j]] = 1;
			if (i % pr[j] == 0) phi[i * pr[j]] = phi[i] * pr[j];
				else phi[i * pr[j]] = phi[i] * (pr[j] - 1ll);
			if (i % pr[j] == 0) break;
		}
	}
	
	for (ll i = 1; i <= 40000; i++)
		phi[i] = phi[i - 1] + phi[i] * 2ll;
	
	
	scanf("%lld", &T);
	
	for (ll i = 1; i <= T; i++) {
    
    
		scanf("%lld", &n);
		printf("%lld %lld %lld\n", i, n, phi[n] + 1);
	}
	
	return 0;
}

Guess you like

Origin blog.csdn.net/weixin_43346722/article/details/114136547