仪仗队 SDOI2008

洛谷的题,没有图。。。。

 

题目描述

作为体育委员,C君负责这次运动会仪仗队的训练。仪仗队是由学生组成的N * N的方阵,为了保证队伍在行进中整齐划一,C君会跟在仪仗队的左后方,根据其视线所及的学生人数来判断队伍是否整齐(如下图)。  现在,C君希望你告诉他队伍整齐时能看到的学生人数。

输入输出格式

输入格式:

共一个数N

输出格式:

共一个数,即C君应看到的学生人数。

输入输出样例

输入样例#1: 复制

4

输出样例#1: 复制

9

说明

【数据规模和约定】

对于 100% 的数据,1 ≤ N ≤ 40000

 

题解:观察图片我们会发现(图片在洛谷上啦),所有在同一条直线上的点只能看到第一个,所以只要枚举每一条直线就行,进一步的,我们发现枚举直线其实也就是如果有两个点的斜率是一样的话,那么后面的点就会被覆盖住;而这些没有被遮挡的点有一个共同点就是,他们行数和列数的gcd值等于1,用欧几里得做,复杂度大概就是O(N^2*longN) 的,大概能骗到好多分,具体的我没试过;

正解就是考虑对这个算法优化,这时我们又发现根本不需要枚举每两个点对,我们只枚举一个数,然后只要知道有多少个数跟他的gcd值等于1就好了,进一步的我们发现这就是欧拉函数;

欧拉函数的定义就是给定一个n,求小于等于n的数中与n  gcd值等于1的数的个数,也就是与n互质的个数;这简直完美解决了这道题目!!!!

代码如下:

#include
#include
#include
#include
#include
using namespace std;
const int maxn=40050;
int cnt;
int vis[maxn+10],prime[maxn+10],phi[maxn+10];
void pri(){//求欧拉函数,我用的线性筛,如果用复杂度稍高的筛法应该也能过
	vis[0]=vis[1]=1;
	phi[1]=1;
	for(int i=2;i<=maxn;i++){
		if(!vis[i]){
			prime[++cnt]=i;
			phi[i]=i-1;
		}
		for(int j=1;i*prime[j]<=maxn&&j<=cnt;j++){
			vis[i*prime[j]]=1;
			if(i%prime[j]==0){
				phi[i*prime[j]]=phi[i]*prime[j];
				break;
			}
			else phi[i*prime[j]]=phi[i]*(prime[j]-1);
		}
		
	}
}
int n;
int main(){
	cin>>n;
	int ans=0;
	if(n==1){
		cout<<0<

 

你可能感兴趣的:(仪仗队 SDOI2008)