首页 > 代码库 > [zroj 51] [Pendulum] : 线性筛

[zroj 51] [Pendulum] : 线性筛

问题描述

Evan 站在巨大的世纪钟摆前,观察着钟摆上方数字的塌缩。他发现,钟摆每摆动?次,上方的数字就会变成把它分解质因数后每一项的和。例如 12 =2 × 2 × 3,那么摆动一次后数字变成 2 + 2 + 3 = 7。现在,上方的数字正好是 x。Evan 还有 y 秒就要去新世界探索了,他想知道在钟摆摆动 y 次到他离开时,上方的数字是多少。

输入格式

 

第一行一个整数n,表示询问个数。后面n行每行两个整数x和y。

输出格式

n行,每行一个答案表示离开时上方的数字。

样例输入

2

5 3

20 1

样例输出

5

9

数据范围

n<=3*10^5,x<=10^7,y<=10^9

一些想法

一句话题意:给定x和y,每次将x质因数分解后的每一项求和作为新的x,问y次后的x

暴力的搞一下10^7以内的所有数进行的变换,发现每个数的变换次数都不超过20次就会变成质数,而我们发现一旦变为了素数或者是4,无论再变换多少次都是不再变的。于是我们使用线性筛,开一个f数组,f[i]表示i质因数分解后的每一项的和。根据分析很明显的知道当i为素数时f[i]=i,当为一个合数为prime[j]*i时f[prime[j]*i]=f[i]+prime[j]。所以最终我们只需要在欧拉筛中插入两句话。

 

 

#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
#define debug(x) cerr<<#x<<‘=‘<<x<<endl
#define MAXN 10000001
#define NUM 669999

int prime[NUM];
bool flag[MAXN];
int x,y,n;
int f[MAXN];

int Euler(int n){
    int cntprime=0;
    memset(flag,false,sizeof(flag));
    memset(f,0,sizeof(f));
    for (int i = 2; i <= n; i++)
    {
        if (!flag[i]) {
            f[i]=i; //第一句 
            prime[++cntprime] = i;
        }
          for (int j = 1; j <= cntprime && prime[j]*i <= n; j++)    {
            f[prime[j]*i]=f[i]+prime[j];
             flag[i*prime[j]] = true;// 第二句 
             if (i % prime[j] == 0) break;
         }
    }
}

int work(int x,int y){
    while (y){
        if (x==f[x]) {//分解为素数时不会再变化 
        ans=x;
        break;
        }
        else ans=x=f[x];
        y--;
    }
    return ans;    
}
    
int main (){
    Euler(MAXN);
    cin>>n;
    for (int i=1;i<=n;i++){
        scanf("%d%d",&x,&y);
        printf("%d\n",work(x,y));
    }
    return 0;
}

 

 

 

 

 


 

 

九月

目击众神死亡的草原上野花一片

远在远方的风比远方更远

我的琴声呜咽 泪水全无

我把这远方的远归还草原

一个叫木头 一个叫马尾

我的琴声呜咽 泪水全无

远方只有在死亡中凝聚野花一片

明月如镜高悬草原映照千年岁月

我的琴声呜咽 泪水全无

只身打马过草原

 

 


 

Sylvia

二零一七年八月九日

 

 

[zroj 51] [Pendulum] : 线性筛