这个题目感觉有点恶心,题目看了40多分钟猜看懂是啥意思,写了一遍又TLE。后来仔细想想,好像是可以预处理:将所有的结果全部存起来,然后再按照每1000个数一段统计各段的符合条件的个数。最后求一下和,再将不能整除的部分逐一判断就行。时间复杂度就会降低很多。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<set>
#define MAX 1000010
#define ll __int64
using namespace std;
ll p[MAX],a[MAX],q[MAX];
bool mark[MAX],sign[MAX],res[MAX];
int main(){
memset(mark,false,sizeof(mark));
memset(sign,false,sizeof(sign));
memset(res,false,sizeof(res));
int c = 0;
for (c = 0; c*4+1<MAX; c++){
p[c] = c*4+1;
mark[p[c]] = true;
}
int u = 0;
for (int i = 1; i<c; i++)
for (int j = i; p[i]*p[j] < MAX; j++) if (mark[p[i]*p[j]]) sign[p[i]*p[j]] = true;
for (int i = 1; i<c; i++) if (mark[p[i]] && !sign[p[i]]) a[u++] = p[i];
//for (int i = 0; i<100; i++) printf("%lld ",a[i]); printf("\n");
for (int i = 0; i<u; i++){
for (int j = i; a[i]*a[j] < MAX; j++) if (mark[a[i]*a[j]] && !res[a[i]*a[j]]){ //
res[a[i]*a[j]] = true;
}
}
int v = 0;
memset(q,0,sizeof(q));
for (int i = 1; i<MAX; i++){
if (i % 1000 == 0){
v++;
}
if (res[i]){
q[v]++;
}
}
int n;
while (scanf("%d",&n) && n != 0){
int ans = 0;
for (int i = 0; i<n/1000; i++) ans += q[i];
for (int i = n/1000*1000; i<=n; i++) if (res[i]) ans++;
printf("%d %d\n",n,ans);
}
return 0;
}