题意:将一个小于等于80000的数分成最多三个素数a,b,c的加和乘,求种类数。没有加括号的情况
题目链接:http://acm.zju.edu.cn/changsha/showProblem.do?problemId=28
思路:比赛的时候一直TLE,拙计啊~~~~
就是在去重的时候,在原来的代码上减少那层循环就好了,只需要统计总共的方案数目,除三就行了,把那些有两个数和三个数相同的情况下,在补齐成三次就行了,从o(n^2)降到了o(n),,,
拙计的代码 ,早点来就好了,
#include <iostream>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>
#include <algorithm>
using namespace std;
#define maxn 80010
#define mode 1000000007
#define LL long long
LL ans;
LL add[maxn];
LL mul[maxn];
bool is[100000];
LL prm[10000];
LL getprm(LL n){
LL i, j, k = 0;
LL s, e = (int)(sqrt(0.0 + n) + 1);
memset(is, 1, sizeof(is));
prm[k++] = 2; is[0] = is[1] = 0;
for (i = 4; i < n; i += 2) is[i] = 0;
for (i = 3; i < e; i += 2) if (is[i]) {
prm[k++] = i;
for (s = i * 2, j = i * i; j < n; j += s)
is[j] = 0;
}
for ( ; i < n; i += 2) if (is[i]) prm[k++] = i;
return k;
}
void init(){
memset(add,0,sizeof(add));
memset(mul,0,sizeof(mul));
for(LL i = 0;i<ans;i++){
for(LL j = i;j<ans ; j++){
if(prm[i]+prm[j]>=maxn) break;
add[prm[i]+prm[j]]++;
}
}
for(LL i = 0;i<ans;i++){
for(LL j = i;j<ans ; j++){
if(prm[i]*prm[j]>=maxn) break;
mul[prm[i]*prm[j]]++;
}
}
}
int main()
{
ans=getprm(80010);
init();
LL n,sum,temp;
while(~scanf("%lld",&n)){
sum = 0;
if(is[n]) sum++;
sum = (add[n] + mul[n] + sum)%mode;
LL res=0,flag2=0,flag3=0;
for(int i=2;i<n;i++){
if(is[i] && add[n-i]){
res=(res+add[n-i])%mode;
if(i*2<n){
if(i*2==(n-i)) flag3+=2;
else
if(is[(n-i-i)]) flag2++;
}
}
}
res = (res + flag3 + flag2);
sum = (sum+res/3) %mode;
res=0; flag3=0,flag2=0;
LL a,b,ji;
for(int i=2;i<n;i++){
if(is[i] && (n%i==0) && mul[n/i]){
res=(res+mul[n/i])%mode;
if(i*i<n){ ji=n/i;
if(ji%i==0){
a=ji/i;
if(is[a]){
if(a==i) flag3+=2;
else flag2++;
}
}
}
}
}
res = (res + flag3 + flag2);
sum = (sum+res/3) %mode;
res=0;
for(int i=2;i<n;i++)
if(is[i] && mul[n-i])
res=(res+1)%mode;
sum = (sum+res) %mode;
printf("%lld\n",sum);
}
return 0;
}