bzoj 2190: [SDOI2008]仪仗队
2190: [SDOI2008]仪仗队
Description
作为体育委员,C君负责这次运动会仪仗队的训练。仪仗队是由学生组成的N * N的方阵,为了保证队伍在行进中整齐划一,C君会跟在仪仗队的左后方,根据其视线所及的学生人数来判断队伍是否整齐(如下图)。 现在,C君希望你告诉他队伍整齐时能看到的学生人数。
Input
共一个数N。
Output
共一个数,即C君应看到的学生人数。
Sample Input
4
Sample Output
9
HINT
【数据规模和约定】
对于 100% 的数据,1 ≤ N ≤ 40000
题解:
n^2的枚举应该是很好写的,先把所有的点都连线,枚举点的坐标,判断gcd(i,j)的值,若大于1即表示中间有点在连线之间
#include<stdio.h> #include<iostream> using namespace std; int n,i,j,ans; int gcd(int a,int b) { if(b==0) return a; if(a%b==0) return b;else gcd(b,a%b); } int main() { scanf("%d",&n); ans=n*n-1; for(i=0;i<n;i++) for(j=0;j<n;j++) if(i!=0||j!=0) { if(gcd(i,j)-1) ans--; } cout<<ans; return 0; }
首先j可以只枚举小于等于i的部分,再乘2(注意i==j的情况)
那么对于当前i的答案就是总数减去与i互质的个数(用欧拉函数)
#include<stdio.h> #include<iostream> #include<math.h> using namespace std; int n,i,j,k,ans,sum,p[40005],a[40004]; int gcd(int a,int b) { if(b==0) return a; if(a%b==0) return b;else gcd(b,a%b); } int main() { scanf("%d",&n); p[1]=1; for(i=2;i<=n;i++) if(p[i]==0) for(j=2;j<=n/i;j++) p[i*j]=1; ans=n*n-1; for(i=2;i<n;i++) { k=0; for(j=1;j<=(int)(sqrt(i));j++) if(i%j==0) { if(p[j]==0) { k++; a[k]=j; } if(i/j!=j&&p[i/j]==0) { k++; a[k]=i/j; } } sum=i; for(j=1;j<=k;j++) sum=sum*(a[j]-1)/a[j]; sum=i-sum; ans-=sum*2+1; } cout<<ans; return 0; }
一念起,天涯咫尺; 一念灭,咫尺天涯。