1020 [SDOI2008]仪仗队 素数筛新模板 欧拉函数
链接:https://ac.nowcoder.com/acm/contest/26656/1020
来源:牛客网
题目描述
作为体育委员,C君负责这次运动会仪仗队的训练。
仪仗队是由学生组成的N * N的方阵,为了保证队伍在行进中整齐划一,C君会跟在仪仗队的左后方,根据其视线所及的学生人数来判断队伍是否整齐(如下图)。
现在,C君希望你告诉他队伍整齐时能看到的学生人数。
输入描述:
共一个数N。
输出描述:
共一个数,即C君应看到的学生人数。
备注:
对于 100% 的数据,1≤N≤400001 \le N \le 400001≤N≤40000
分析
首先了解到当有一条线来到某个点的时候,这个点的横坐标和纵坐标是互质的,否则横坐标和纵坐标除上他们公共的最小质因子会得到一个新的正确的坐标,这样这个点就跟另一个点在一条线上了。
然后上半部分和下半部分是完全一致的,所以先只看横坐标 >= 纵坐标的部分。
随着横坐标的增大,满足条件的纵坐标数目(就是跟横坐标互质的那些纵坐标)是横坐标的欧拉函数个。
所以只要把1到n 的欧拉函数加起来就可以了。由于这题横坐标从0开始,所以n 要减去1,最后答案乘二再 + 3 (分别是(1,0),(0,1),(1,1))
欧拉函数,两个数互质的时候是积性函数,所以pi[a*b] = pi[a] * pi[b]
当a是质数的时候,pi[a] = a - 1
当它是合数的时候,由于素数筛在跳出循环之前,primes[j] 都是和i大多数互质的(有特例),所以 pi[primes[j] * i] 是满足条件的积性函数,pi[primes[j] * i] = pi[primes[j]] * pi[i];
但是由于素数筛会在i % primes[j] == 0 的时候照例筛掉primes[j] * i ,由于这个时候i 和 primes[j] 不是互质的,所以要特判一下,从公式出发,
pi[N] = N(1-1/p1)(1-1/p2)(1-1/p3)....,并且 这个时候,primes[j] * i 的质因子和 i 的质因子完全一样,所以pi[primes[j] * i] = primes[j] * pi[i];
这个新的素数筛模板改动了st的意思,原本的意思是这个数有没有被筛掉,现在的意思是这个数的最小质因子是什么。
//-------------------------代码---------------------------- //#define int ll const int N = 2e6+10; int n,m; int cnt; int st[N],pi[N]; int primes[N]; void solve() { cin>>n; n -- ; for(int i = 2;i<=n;i++) { if(!st[i]) { st[i] = i; primes[cnt ++ ] = i; pi[i] = i - 1; } for(int j = 0;j < cnt && i * primes[j] <= n;j ++ ) { st[primes[j] * i] = primes[j]; if(st[i] == primes[j]) pi[primes[j] * i] = pi[i] * primes[j]; else pi[primes[j] * i] = pi[primes[j]] * pi[i]; } } int ans = 0; for(int i = 1;i<=n;i++) { ans += pi[i]; } ans *= 2; ans += 3; cout<<ans<<endl; } signed main(){ clapping();TLE; // int t;cin>>t;while(t -- ) solve(); // {solve(); } return 0; } /*样例区 */ //------------------------------------------------------------