【题意】两个士兵在玩一个游戏,第一个士兵有一个数字n,然后第二个士兵选择一个能够整除n的数x(必须是整除不能有余数),然后n = n/x;一直这样循环下去,直到n == 1,然后第二个士兵的得分是这个游戏能够持续的回合数。第一个士兵最开始取的n= a!/b! 求第二个士兵最大的得分。
【分析】表示完全没看懂题目,后来翻题解才看懂,英语太渣。由于T很大,只能先预处理再O(1)求每个(a,b);而因为要除的次数尽量多,每次选择的除数肯定是越小越好,则发现把n分解成质因数相乘的质因数个数就是最大循环轮数。但是还有个问题需要O(1)计算出a!/b! 似乎不太可能?a!/b!就是a*(a-1)*(a-2)*(b+1);就是b+1~a的所有分解出的质因数个数和呀。前缀和解决!关于单个分解,用dp[i] = dp[i/tmp]+1(tmp是最小的整除i的素数);
【AC CODE】857ms
#include <cstdio> #include <cstring> #include <cctype> #include <cmath> #include <set> //#include <unordered_set> #include <queue> #include <stack> #include <vector> #include <string> #include <algorithm> using namespace std; typedef long long LL; #define rep(i,a,n) for(int i = a; i < n; i++) #define repe(i,a,n) for(int i = a; i <= n; i++) #define per(i,n,a) for(int i = n; i >= a; i--) #define clc(a,b) memset(a,b,sizeof(a)) const int INF = 0x3f3f3f3f, MAXN = 5000000; char buf[MAXN], *ps = buf,*pe = ps+1; inline void rnext(){ if(++ps == pe){ pe = (ps = buf)+fread(buf,1,sizeof(buf),stdin); } } inline int in() { do{ rnext(); }while(!isdigit(*ps) && ps != pe); int ans = 0; do{ ans = (ans<<1)+(ans<<3)+*ps-48; rnext(); }while(isdigit(*ps) && ps != pe); return ans; } int dp[MAXN+10], prime[MAXN+10]; LL sum[MAXN+10]; void getprime() { for (int i = 2; i <= MAXN; i++) { if (!prime[i])prime[++prime[0]] = i; for (int j = 1; j <= prime[0] && prime[j] <= MAXN / i; j++) { prime[prime[j] * i] = 1; if (i%prime[j] == 0) break; } } } int main() { #ifdef SHY freopen("d:\\1.txt", "r", stdin); #endif int t = in(); getprime(); repe(i,1,prime[0]) dp[prime[i]] = 1; repe(i,4,MAXN) { int tmp = i; if(binary_search(prime+1,prime+1+prime[0],i)) continue; for(int j = 1; j <= prime[0] && prime[j] <= tmp; j++) { if(0 == tmp%prime[j]) { dp[i] = dp[tmp/prime[j]]+1; break; } } } repe(i,1,MAXN) sum[i] = sum[i-1]+dp[i]; while(t--) { int a = in(),b = in(); printf("%I64d\n", sum[a]-sum[b]); } return 0; }