能想到O(n(logn)^2)就差不多了,至于O(nlogn)真的好难想到。。。只能说先暴力,然后再找规律不失为一个好方法吧。
类似素数筛法的算法的复杂度都是O(nlogn)。因为n/2+n/3+...+n/n=n*(1/2+1/3+...+1/n)。根据调和级数的性质,1/2+1/3+...+1/n约等于lnn。所以复杂度为O(nlogn)。
具体思路看紫书吧。
预处理的技巧也非常值得学习。
for(int i=1;i<=30000000;i++)
for(int j=i+i;j<=30000000;j+=i)
if(j==(i^(j-i))) ans[j]++;
这段代码计算的是两个数中较大的那个数(也就是a)为j时的答案个数。
for(int i=2;i<=30000000;i++) ans[i]+=ans[i-1];
累积求和一下就可以得到小于N的总个数了。
代码
#include<bits/stdc++.h>
using namespace std;
int N;
int kase;
int ans[30000010];
void init()
{
for(int i=1;i<=30000000;i++)
for(int j=i+i;j<=30000000;j+=i)
if(j==(i^(j-i))) ans[j]++;
for(int i=2;i<=30000000;i++) ans[i]+=ans[i-1];
}
int main()
{
init();
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d",&N);
printf("Case %d: %d\n",++kase,ans[N]);
}
}