题意:给你一个n*n的网格,任意一点和(0,0)连线,可以组成一条直线,前面的点可以挡住后面的点,问你从原点能看到的点到底有多少个
分析:这道题一开始没用欧拉函数做,先用的递推打表的方法,由后一个和前一个的关系得出结果,
其实这是一个很明显的欧拉函数题(菜鸡没发现),我们可以把整个坐标系以 y=x 直线分为两部分,然后求出下半部分的点在乘2就好了,我们可以发现符合条件的点的X,Y坐标必须是互质的,所以就可以利用欧拉函数了,对于横坐标2->n求出对应每个横坐标的互质的纵坐标,然后乘2相加。
递推代码:
#include <map>
#include <set>
#include <cmath>
#include <queue>
#include <stack>
#include <cstdio>
#include <vector>
#include <iomanip>
#include <cstdlib>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#define ll long long
#define mod 1000000007
#define mem(a) memset(a,0,sizeof(a))
using namespace std;
typedef pair <int,int> pii;
const int maxn = 1000 + 5 , inf = 0x3f3f3f3f;
int cnt[maxn];
int gcd(int a,int b){
return b==0?a:gcd(b,a%b);
}
void cal(){
mem(cnt);
cnt[1]=3;
cnt[2]=5;
for(int i=3;i<=1000;i++){
int ans = 0;
for(int j=1;j<i;j++){
if(gcd(i,j)==1) ans+=2;
}
cnt[i]=cnt[i-1]+ ans;
}
}
int main(){
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int T;
// Init();
cal();
scanf("%d",&T);
int k = 1;
while(T--){
int n;
scanf("%d",&n);
printf("%d %d %d\n",k++,n,cnt[n]);
}
}
欧拉函数代码:
#include <map>
#include <set>
#include <cmath>
#include <queue>
#include <stack>
#include <cstdio>
#include <vector>
#include <iomanip>
#include <cstdlib>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#define ll long long
#define mod 1000000007
#define mem(a) memset(a,0,sizeof(a))
using namespace std;
typedef pair <int,int> pii;
const int maxn = 1000 + 5 , inf = 0x3f3f3f3f;
int euler[maxn];
void Init()
{
memset(euler,0,sizeof(euler));
euler[1] = 1;
for(int i = 2;i<maxn;i++){
if(!euler[i]){
for(int j = i;j<maxn;j+=i){
if(!euler[j])euler[j] = j;
euler[j] = euler[j]/i*(i-1);
}
}
}
}
int main(){
// freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int T;
int k = 1;
Init();
scanf("%d",&T);
while(T--){
int n,sum = 1;
scanf("%d",&n);
for(int i=1;i<=n;i++){//这里i代码横坐标,欧拉函数值代表纵坐标
// cout<<i<<" "<<euler[i]<<endl;
sum=sum+euler[i]*2;
}
cout<<k++<<" "<<n<<" "<<sum<<endl;
}
}