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);
    	}
    }
    
  • 相关阅读:
    基于RSA securID的Radius二次验证java实现(PAP验证方式)
    一些指令 & 一些知识 (Linux Spring log4j...)
    RSA, ACS5.X 集成配置
    Python中的动态属性与描述符
    设计模式(一):单例模式
    JavaWeb
    动态规划_背包问题
    动态规划_最长上升子序列
    MySQL复习
    动态规划_数字三角形
  • 原文地址:https://www.cnblogs.com/caijiLYC/p/13970799.html
Copyright © 2011-2022 走看看