zoukankan      html  css  js  c++  java
  • [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
    ",ans);
    	}
    }
    
  • 相关阅读:
    《常微分方程,王高雄》 习题 1.5,1.8(2)
    微分方程及边值问题:计算与建模 习题1.17-1.31
    打造自己备份的系统镜像
    打造自己备份的系统镜像
    ★一名“标题党”自我修炼的10大技巧
    ★一名“标题党”自我修炼的10大技巧
    ★数学上最大的数是多少?
    ★不容错过的PPT教程!
    ★不容错过的PPT教程!
    【★】电子产品降价的3大原因!
  • 原文地址:https://www.cnblogs.com/caijiLYC/p/13970799.html
Copyright © 2011-2022 走看看