题目链接:http://lightoj.com/login_main.php?url=volume_showproblem.php?problem=1336
题目大意:求1~n中,约数和为偶数的数字个数
题目思路:根据唯一分解定理,约数和为f(x)= (1+p1+p1^2+p1^3+...+p1^a1)*(1+p2+p2^2+...+p2^a2)*...*(1+pn+pn^2+...+pn^an);
只有奇数乘以奇数才能还是奇数,所以每个括号内的值都应该是奇数
所以考虑奇数的情况,用n减去就行
质数只有2是偶数,所以2所在的那一项除了1都是偶数,整个项一定为奇数,所以2^x一定符合要求
而对于不是2的质数,当他们有偶数个时,整个项为奇数,而奇数个时,整个项为偶数
所以就需要找出所有除了2的质因数为偶数个的情况
而当他们为偶数时,就一定是一个平方数,如果他们还有2,2的数量为奇数时,就是2*一个平方数,否则就是平方数本身
2^x一定属于平方数或2*平方数
所以找出n内所有平方数和2*平方数即可
除暴力外,还可以直接通过公式o1得到,平方数个数就直接开根号即可,而2*平方数个数就直接对/2结果开根号即可
以下是代码:
暴力:
#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define rep(i,a,b) for(ll i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
#define ll long long
const int MAXN = 1e7+5;
const int MOD =1e9+7;
int main(){
int t;
ll n;
scanf("%d",&t);
rep(_,1,t){
scanf("%lld",&n);
ll ans=n;
rep(i,1,sqrt(n)){
if(i*i<=n)ans--;
if(2*i*i<=n)ans--;
}
printf("Case %d: %lld\n",_,ans);
}
return 0;
}
公式:
#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
#define ll long long
const int MAXN = 1e7+5;
const int MOD =1e9+7;
int main(){
int t;
ll n;
scanf("%d",&t);
rep(_,1,t){
scanf("%lld",&n);
ll ans=(ll)sqrt(n)+(ll)sqrt(n/2);
printf("Case %d: %lld\n",_,n-ans);
}
return 0;
}