[HAOI2012] 外星人

  这题我考场上绝对打30分暴力,有时间的话会再想想60分。

  一年前我题都看不懂,一个月前能五分钟码完30分暴力,这也算进步了吧。

  首先根据题目的公式,可以发现,只要质因子不是2,每Φ一次,生成一个偶数 ( p-1 ) ,而这个偶数可以分解成2的次幂乘上一个质数。

而容易得到 Φ(2n) = n,因此只要我们知道最后化成了2的几次幂以及化了几轮,两者加起来即为答案。

  注意到:

  1:每个质因子最后化成的2的幂次是独立的,因此我们可以单独处理每个质因子,也照应了题目的输入。

  2:设质因子 p 最终化成了 2n,那么 pq 最终会化成 2n*q,成功的处理了单个质因子的情况。

  下来重点就是如何求质因子 p 最终会化成 2 的几次幂,以及化的轮数。

  前者我们可以想到用类似于筛素数的方法(反正考场上我想不到),用 f[i] 表示在 i 的化形过程中产生的2的次幂总数,f[i] = f[i - 1 ] ( i 为素数 ),f[i*prime[j]] = f[i] + f[prime[j]],这个式子如果给出的话是比较好理解的,因为乘法对应的2的幂次是加起来,但是自己想的话我是想不出来。

  这样解决了质因子 p 的问题。

  接下来我们考虑轮数。

  这次我们不单个单个质因子考虑,直接考虑整体。( 其实单个也一样,单个是只有1个质因子的整体 )

  我们发现,假如原数本身即包含质因子2,那么每一轮会产生多个2并减少1个2。

  假设最终得到的2的次幂为 n,进行了 q 轮,共新产生的2的次幂为 m 。(注意是新产生的)

  可以列出以下式子:m - q = n。而我们要求的 ans = n + q,恰好等于 m,也就是产生的2的次幂数,这刚好与我们上文所求的 f[] 函数对应!

  接着我们考虑原数本身不包含质因子2的情况。

  注意到在这样一个数的第一次Φ过程中,因为本身不含质因子2,所以2的次幂只增加而并没有减少1,在第一次Φ之后便产生了质因子2,所以总共减少的2的次幂数为 q-1。

  对应的,我们可以列出如下等式,变量意义同上:m - ( q - 1 ) = n,ans = n + q = m + 1,也就是产生的2的幂次数加1,依然可以通过上文所求的 f[] 函数解决。

  综上,我们可以得到答案的表达式。

  ans = Σ f[p] * q            ( pmin == 2 )

  ans = 1 + Σ f[p] * q      ( Pmin != 2 )

  至此,终于圆满的解决了本题。

  再次提醒自己,注意中间变量爆 int !

// q.c
// 日常中间变量爆int...

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
const int M=100000;
int cnt,prime[M+10],f[M+10];
void prepare() {
	f[1]=1;
	for(int i=2;i<=M;i++) {
		if(!f[i]) {
			f[i]=f[i-1];
			prime[++cnt]=i;
		}
		for(int j=1;j<=cnt&&i*prime[j]<=M;j++) {
			f[i*prime[j]]=f[i]+f[prime[j]];
			if(i%prime[j]==0) break;
		}
	}
}
int main() {
	freopen("alien.in","r",stdin);
	freopen("alien.out","w",stdout);
	int T,m,a,b,delta; long long ans;
	scanf("%d",&T);
	prepare();
	for(int i=1;i<=T;i++) {
		delta=1,ans=0;
		scanf("%d",&m);
		for(int i=1;i<=m;i++) {
			scanf("%d%d",&a,&b);
			if(a==2) delta=0;
			ans+=(long long)f[a]*b; // 炸.
		}
		printf("%lld\n",ans+delta);
	}
	return 0;
}

 

posted @ 2018-04-15 17:37  qjs12  阅读(97)  评论(0编辑  收藏  举报