一个好玩的题目
首先理解一下题意,就是说每次会给你一个数(被分解成其质因数乘积的形式),求对它用几次欧拉函数能使其变成(1)
例如样例 (N=2^2*3^1=12)
(12->4->2->1) 一共三次
又发现题目给了这玩意
[varphi(prod_{i = 1}^m p_i^{q_i}) = prod_{i = 1}^m (p_i - 1)*p_i^{q_i-1}
]
发现一个性质:每次操作就是将其除以其所有质因数之积,再乘上它们减一后的积
比如对于(N=60)时,一次操作就是((60/5/6/2)*4*5*1)
然后就发现,若(N)为合数,在每次操作中会(仅)使(N)中的一个(2)变为(1)
否则(N)会减一
于是我们记录每个数中有几个(2),比如说(5),(5->4->2*2)这么看有两个(2)
对于偶数,将其变为(1)的步数就是其(2)的个数
否则还要减一,就像上面(5)的例子一样
那么这个规律怎么和题目联系起来呢
因为每次最多使一个(2)变为(1),但是一个数"产出"(2)的回合数最多是(2)(还是看(5)的例子,(5)只需要一回合就能变成(2)的倍数)
所以一定会有很多多余的(2),那么我们就发现了,(N)变唯一的回合数就是把(2)都给搞定的回合数
设(f)数组记录每个数能"生产"几个(2)
[f[a]=f[a-1](a为质数)
]
[f[a*b]=f[a]+f[b]
]
然后对于(N),我们只需要知道它的质因子们会提供几个(2),再按上面法则计算就好
#include<iostream>
#include<cstdio>
#include<cstring>
#define ll long long
using namespace std;
const ll N=2e5;
ll n,m,f[N],a[N],top,T,ans;
bool pook[N],pool;
int main(){
f[1]=1;
for(ll i=2;i<=1e5;i++){
if(!pook[i]){
f[i]=f[i-1],a[++top]=i;
}
for(ll j=1;j<=top&&i*a[j]<=1e5;j++){
pook[a[j]*i]=1,f[a[j]*i]=f[a[j]]+f[i];
if(i%a[j]==0)break;
}
}
scanf("%lld",&T);
while(T--){
scanf("%lld",&n);
pool=0,ans=1;
for(ll i=1,a1,a2;i<=n;i++){
scanf("%lld%lld",&a1,&a2);
ans+=f[a1]*a2;
if(a1==2)pool=1;
}
ans-=(pool==1);
printf("%lld
",ans);
}
}