分析:题目并不难理解,就是一些细节上的优化需要我们注意,我在没有优化前跑了2000多MS,优化了一些细节后就是400多MS了,之前还TLE了好几次。
方法:将整数拆分为质因子以后,表达为这样的形式,e1*p1 + e2*p2 + .... + en*pn,整数的所有约数的个数为(1+p1)*(1+p2)*(1+pn);
注意:当时我也在担心,题目中要求我们的分解成的两个数不能相等,但是当我们求出约数总数以后直接除了2(因为我们只需要一半),没有特殊处理相等的情况,会不会出错? 其实不会,我们这个是整除2,巧妙的把中间的约数挖去了,举个例子吧,4的约数有(1,2,4)三个,这里能用的只有(1,4)这一组,3/2 = 1,正好是正确答案。这里是一个细节,应该注意到。
具体的一些细节表示在下面的代码里:
#include<iostream> #include<cstdio> #include<cmath> #include<cstring> using namespace std; #define LL long long///数据比较强,建议LL #define maxn 1000010///质因子,所有sqrt(1^12) = 1^6就够了 LL is_prime[maxn],prime[maxn],cnt; void make_prime() { memset(is_prime,1,sizeof(is_prime)); is_prime[1] = 0; cnt = 0; for(int i = 2; i <= maxn; i++) { if(is_prime[i]) { prime[cnt++] = i;///建议在这就记数 for(int j = 2*i; j <= maxn; j += i) is_prime[j] = 0; } } } LL slove(LL num) { LL sum = 1; for(int i = 0; i < cnt && prime[i]*prime[i] <= num; i++)///质因子一定满足平方小于等于原数 { ///尽量使用乘积的形式,这里不会溢出,而根号有精度或者其他问题,当时我开了根号居然是超时…… int tot = 0; if(num == 1) break;///及时退出 while(num % prime[i] == 0) { num /= prime[i]; tot++; } sum *= (tot+1); } if(num > 1) sum *= 2; return sum; } int main() { int t,ca = 0; LL a,b; make_prime(); scanf("%d",&t); while(t--) { scanf("%lld%lld",&a,&b); if(a < b*b)///注意这个小小的判断,它会节省很多时间。 { printf("Case %d: 0 ",++ca); continue; } LL num = slove(a); num /= 2; /// 整除 for(LL i = 1; i < b; i++)///我们还要去掉不满足的解 { if(a % i == 0) num--; } printf("Case %d: %lld ",++ca,num); } return 0; }