[HAOI2012]外星人题解

一个好玩的题目
首先理解一下题意,就是说每次会给你一个数(被分解成其质因数乘积的形式),求对它用几次欧拉函数能使其变成\(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\n",ans);
	}
}
posted @ 2020-11-13 18:35  蒟蒻丁  阅读(70)  评论(0编辑  收藏  举报