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\n",sum[a]-sum[b]);
40     }
41     return 0;
42 }
43 
44 int sb=hh();
45 int main(int argc,char**argv) {;}
代码

 

转载于:https://www.cnblogs.com/whistle13326/p/7521962.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值