欧拉函数
最开始想的肯定是打表找规律,发现没啥规律(因为上次那个差分序列的题还写了半天出现一次出现两次出现四次)。
意思就是已知某数字与它互质且小于它的数共有m个,求在所有符合情况的数字中最小的那一个。我想把phi[a] = p记录下来,然后按照p排序,return a,最后将所有值相加。但是实现的时候比较麻烦,因为p不是连续的,而且也不单调,怎么确定最小的a就很难搞。这种思路硬搞也可以的题解
卡了半天看了题解之后发现是利用了欧拉函数的一个性质:
若A是素数,则phi(A) = A - 1(跟除了它自己之外的互质)。
如果phi[A] = m,m存在,那么第一个使得phi[ num[t] ] = m的num[t]一定是素数。又因为我们要取min{num[1], num[2]…}所以只要对素数进行处理就好啦。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int MAX_N = 1000010;
int T, n, cnt;
ll ans;
int isprime[MAX_N], cprime[MAX_N];
void prime()
{
memset(isprime, 1, sizeof(isprime));
isprime[1] = isprime[0] = 0;
for(int i = 2;i <= MAX_N;i++)
{
if(isprime[i])
{
for(int j = i+i;j <= MAX_N;j += i)
isprime[j] = 0;
cprime[cnt++] = i;
//printf("cprime[%d] = %d\n", cnt-1, i);
}
}
}
int bisearch(int i)
{
int l = 0, r = cnt, mid;
while(l <= r)
{
mid = (l + r)/2;
//printf("l = %d r = %d mid = %d\n", l, r, mid);
if(cprime[mid] > i)
r = mid - 1;
else
l = mid + 1;
}
//printf("l = %d r = %d mid = %d\n", l, r, mid);
for(int w = r; ;w++)
if(cprime[w] > i)
{
//printf("return cprime[%d] = %d\n", w, cprime[w]);
return cprime[w];
}
}
int main()
{
prime();
scanf("%d", &T);
for(int i = 1;i <= T;i++)
{
ans = 0;
scanf("%d", &n);
for(int m = 1;m <= n;m++)
{
int x;
scanf("%d", &x);
ans += bisearch(x);
//printf("ans = %lld\n", ans);
}
printf("Case %d: %lld Xukha\n", i, ans);
}
return 0;
}