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) {;}
作者:乌鸦坐飞机
出处:http://www.cnblogs.com/whistle13326/
新的风暴已经出现
怎么能够停止不前
穿越时空 竭尽全力
我会来到你身边
微笑面对危险
梦想成真不会遥远
鼓起勇气 坚定向前
奇迹一定会出现