CF396E On Iteration of One Well-Known Function [欧拉函数 III]
给出 , 求 .
因为 ,
所以对一个整数 进行一次 操作即
- 乘一次 , 即项的幂数减 .
- 乘一次 , 对 分解质因数, 使得对应的较小的质数的幂数增加若干.
那么怎么快速地去求解本题的式子呢?
从小到大共有个质数, 对每个质数单独处理,
设当前质数为 , 还需进行 次 操作, 指数为 ,
为保证效率最大化, 将 进行 次 操作,
这样会使得 分解, “散落” 到比 更小的质数中,
所以需要循环往复地对每个质数进行这个操作, 直到没有任何质数有操作的余地 .
对当前 , 若进行了 次 操作, 则需要在指数为 时, 次操作不去减 , 因为可能还有指数不为 的希望,
过了 后若指数仍然为 , 表示没救了, 需要使 减小 .
在质数筛时记录每个数 的最小质因子 , 分解质因数时, 就可以利用 直接分解 .
记得在开始时每个质数的 都为 , 因为每个质数都有可能参与运算 .
#include<cstdio>
#include<algorithm>
#define reg register
typedef long long ll;
const int maxn = 1e6+5;
int M;
int p_cnt;
int p[maxn];
int q[maxn];
int Mp[maxn];
int come[maxn];
ll K;
ll a[maxn];
ll SOS[maxn];
ll left[maxn];
void Sieve(){
for(reg int i = 2; i < maxn; i ++){
if(!come[i]) come[i] = i, p[++ p_cnt] = i, Mp[i] = p_cnt;
for(reg int j = 1; j <= p_cnt && i*p[j] < maxn; j ++){
int t = i*p[j];
come[t] = p[j];
if(i % p[j] == 0) break ;
}
}
}
int main(){
//freopen("a.out", "w", stdout);
Sieve();
scanf("%d", &M);
for(reg int i = 1; i <= M; i ++){
scanf("%d", &q[i]);
scanf("%I64d", &a[Mp[q[i]]]);
}
scanf("%I64d", &K);
for(reg int i = 1; i <= p_cnt; i ++) left[i] = K;
bool flag = 1;
while(flag){
flag = 0;
for(reg int i = 1; i <= p_cnt; i ++)
if(a[i]){
if(!left[i]) continue ;
ll t = std::min(a[i], left[i]);
a[i] -= t, left[i] -= t;
SOS[i] += t-1, flag = 1;
int tmp = p[i]-1;
while(tmp != 1){
int id = Mp[come[tmp]];
a[id] += t;
tmp /= come[tmp];
}
}else if(SOS[i]) SOS[i] --;
else if(left[i])left[i] --;
}
int Ans = 0;
for(reg int i = 1; i <= p_cnt; i ++) if(a[i]) Ans ++;
printf("%d\n", Ans);
for(reg int i = 1; i <= p_cnt; i ++)
if(a[i]) printf("%d %I64d\n", p[i], a[i]);
return 0;
}