• 1441 士兵的数字游戏


                                                  1441 士兵的数字游戏

    基准时间限制:6 秒 空间限制:131072 KB 分值: 40 难度:4级算法题

    两个士兵正在玩一个游戏,游戏开始的时候,第一个士兵为第二个士兵选一个正整数n。然后第二个士兵要玩尽可能多的轮数。每一轮要选择一个正整数x>1,且n要是x的倍数,然后用n/x去代替n。当n变成1的时候,游戏就结束了,第二个士兵所得的分数就是他玩游戏的轮数。为了使游戏更加有趣,第一个士兵用 a! / b! 来表示n。k!表示把所有1到k的数字乘起来。那么第二个士兵所能得到的最大分数是多少呢?
     
     
    Input
    单组测试数据。
    第一行包含一个整数t (1 ≤ t ≤ 1,000,000),表示士兵玩游戏的次数。
    接下来t行,每行包含两个整数a,b (1 ≤ b ≤ a ≤ 5,000,000)。
    Output
    对于每一组数据,输出第二个士兵能拿到的最多分数。
    Input示例
    2
    3 1
    6 3
    Output示例
    2
    5


    显然 士兵每次要选择最小的质因子 才能使游戏轮数最大 自己可以算一下

    看到时限6s 我第一想法是 1s内跑素数筛 然后 剩下的时间处理结果
    但是 20个点全TLE了(T_T)

    实际上 我们知道这个这个 阶乘除阶乘 用处不大 我们可以把它转化一下
    如果我们用质因子的幂次方来表示阶乘 那么这个式子就相当于 上面质因子的个数减去下面质因子的个数

    所以我们可以用前缀和sum[i]来表示 i的阶乘的所有质因子的个数
    我们既要筛素数 (因为求质因子个数时要用到素数表) 还要求每个数的质因子个数 (前缀和无法直接求出)

    我们想到了欧拉筛法 欧拉筛法可以保证 每个数只会被他最小的素因子筛掉 也就是每个数只会被筛一次

    prime[]数组中的素数是递增的,当i能整除prime[j],那么i*prime[j+1]这个合数肯定被prime[j]乘以某个数筛掉。
       因为i中含有prime[j],prime[j]比prime[j+1]小,即i=k*prime[j],那么i*prime[j+1]=(k*prime[j])*prime
       [j+1]=k’*prime[j],接下去的素数同理。所以不用筛下去了。因此,在满足i%prime[j]==0这个条件之前以及第一次
       满足改条件时,prime[j]必定是prime[j]*i的最小因子。
    为什么只会被筛一次

    在进行欧拉筛法的同时 我们统计每个数的素因子个数 最后在统计一次前缀和 

    O(1) 查询 

    预期 可以在2s内跑过 但实际上每个点最少跑了3s 连5s的都有 

    可能是取模运算吧(疑惑脸)

     1 #include <cstdio>
     2 #include <cctype>
     3 
     4 const int MAXN=5000010;
     5 
     6 int T,a,b,top;
     7 
     8 int prime[MAXN],sum[MAXN],t[MAXN];
     9 
    10 bool vis[MAXN];
    11 
    12 inline void read(int&x) {
    13     int f=1;register char c=getchar();
    14     for(x=0;!isdigit(c);c=='-'&&(f=-1),c=getchar());
    15     for(;isdigit(c);x=x*10+c-48,c=getchar());
    16     x=x*f;
    17 }
    18 
    19 inline void Pre() {
    20     for(int i=2;i<MAXN;++i) {
    21         if(!vis[i]) prime[++top]=i,t[i]=1;
    22         int u=i;
    23         for(int j=1;j<MAXN&&i*prime[j]<MAXN;++j) {
    24             vis[i*prime[j]]=true;
    25             t[i*prime[j]]=t[i]+t[prime[j]];
    26             if(i%prime[j]==0) break;
    27         }
    28     }
    29     sum[1]=0;sum[2]=1;
    30     for(int i=3;i<MAXN;++i) sum[i]=sum[i-1]+t[i];
    31     return;
    32 }
    33 
    34 int hh() {
    35     read(T);
    36     Pre();
    37     while(T--) {
    38         read(a);read(b);    
    39         printf("%d
    ",sum[a]-sum[b]);
    40     }
    41     return 0;
    42 }
    43 
    44 int sb=hh();
    45 int main(int argc,char**argv) {;}
    代码
  • 相关阅读:
    (转)怎样获得与激活Windows 7超级管理员权限
    (转) C代码优化方案
    英语词汇立体记忆 02
    (转)LUA和C之间的函数调用
    通过lua自带例子学习lua 01
    英语词汇立体记忆 01
    反射(类加载内存分析)
    反射(类加载器的作用)
    反射(动态创建对象操作属性)
    反射(分析类初始化)
  • 原文地址:https://www.cnblogs.com/whistle13326/p/7521962.html
Copyright © 2020-2023  润新知