题意:给定$n=\prod\limits_{i=1}^mp_i^{a_i}$,求$\varphi\left(\cdots\varphi\left(n\right)\cdots\right)$(有$k$个$\varphi$)
因为$\varphi(n)=n\prod\limits_{i=1}^m\dfrac{1-p_i}{p_i}$,所以每次对一个数$n$取$\varphi$,就相当于对它的每个质因数$p$,把$n$乘上$\dfrac{p-1}p$
先筛出$10^6$内的质数,然后对$n$的每一个的质因子分别考虑
记$c_p$为当前$n$的质因数分解式中$p$的指数,$k_p$为还要对$p$这个指数执行多少次$\varphi$,每次比较$c$和$k$,可以一次执行$t=\min(c_p,k_p)$次$\varphi$(一次砍掉$t$个$p$),再把$(p-1)^t$的质因数分解加到对应的$c$即可
这样做会带来一个问题:我们执行$\varphi$时必须要用$n$的质因子$p$,而用到的$p$可能来自最近的几次质因数分解$p-1$,而这几次分解并未完全分解,所以我们对于某些执行$\varphi$多次的$p$要暂缓执行(等待之前的$p-1$被分解完),记$skip_p$表示对于$p$要跳过多少次执行$\varphi$,每次如果可以执行,那么就用$t-1$更新$skip_p$(执行完这次,还要等待$t-1$波分解其他质因子就可以继续了),否则按$skip_p$跳过几次,这样可以保证每次执行$\varphi$都优先使用原来的$p$,最后再把$p-1$分解留到以后使用
数据范围很吓人,可是这样是挺快的2333(因为如果要执行$\varphi$一次就是$\min(c_p,k_p)$,所以这两个数都减小得很快)
2018.3.28补充一些东西
$\varphi\left(\prod\limits_{i=1}^kp_i^{a_i}\right)=\prod\limits_{i=1}^k\varphi\left(p_i^{a_i}\right)=\prod\limits_{i=1}^kp_i^{a_i-1}\left(p_i-1\right)$
第一次取$\varphi$,我们可以对每个质因数分开考虑,之后的取$\varphi$操作就要小心了,如果我们对原来的$p_i$执行$\varphi$,由此产生的$p_i-1$分解之后会加到更小的$p_i$上
所以,①我们要从小到大枚举$p_i$做$\varphi$操作(因为$p_i-1$分解成更小的质数)②一次性对$p_i$做完$t$次$\varphi$之后,接下来如果当前没有$p_i$这个因子,我们要跳过这些操作(总共跳过$t-1$次)而不是直接把$k_{p_i}-1$(因为接下来同一阶段的其他的$p_i-1$分解之后有可能落到这里,我们不能忽略掉这些“新来的”$p_i$)
#include<stdio.h>
typedef long long ll;
const int T=1000000;
int p[1000010],f[1000010];
ll c[1000010],k[1000010],skip[1000010];
ll min(ll a,ll b){return a<b?a:b;}
int main(){
int m,M,i,j,x;
ll t;
bool flag;
for(i=2;i<=T;i++){
if(f[i]==0){
M++;
p[M]=i;
f[i]=i;
}
for(j=1;p[j]<=f[i]&&p[j]*i<=T&&j<=T;j++)f[p[j]*i]=p[j];
}
scanf("%d",&m);
while(m--){
scanf("%d",&x);
scanf("%I64d",c+x);
}
scanf("%I64d",&t);
for(i=1;i<=T;i++)k[p[i]]=t;
do{
flag=0;
for(i=1;i<=T;i++){
x=p[i];
if(c[x]){
if(k[x]==0)continue;
t=min(c[x],k[x]);
c[x]-=t;
k[x]-=t;
skip[x]+=t-1;
flag=1;
x--;
while(x>1){
c[f[x]]+=t;
x/=f[x];
}
}else if(skip[x])
skip[x]--;
else if(k[x])
k[x]--;
}
}while(flag);
x=0;
for(i=1;i<=T;i++){
if(c[p[i]])x++;
}
printf("%d\n",x);
for(i=1;i<=T;i++){
if(c[p[i]])printf("%d %I64d\n",p[i],c[p[i]]);
}
}