D - Sigma Function
这道题一看到就和上一道题很像,以为也是算数基本定理的考查,做了一下,发现能过样例……tle……
tle的思路:经过多次验算???就是发现幂的规律吧,只要存在一个pi,ei都为奇数的pi^ei,就能使sum为偶数。(素因子分解后,全为奇 ^ 偶,偶 ^ 偶,偶 ^ 奇,因子和就是奇数。)
tle的代码做个借鉴:
//输出格式没改
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define MAX 1000005
#define mod 1000000007
using namespace std;
long long p[MAX],v[MAX],num_prime;
void GetPriem()//获得素数
{
memset(p,0,sizeof(p));
memset(v,0,sizeof(v));
for(int i=2;i<MAX;i++)
{
if(!v[i])
{
p[++num_prime]=i;
for(int j=i;j<MAX;j+=i)
v[j]=1;
}
}
}
long long Ans(long long n)
{
long long cnt,sum=0;
for(int i=1;i<=num_prime && p[i]<=n;i++)
{
if(n%p[i]==0)
{
cnt=0;
while(n%p[i]==0)
{
cnt++;
n/=p[i];
}
if(cnt % 2 != 0 && p[i] % 2 != 0)
{
sum = 1;
}
}
}
if(n > 1)
sum = 1;
return sum;
}
int main()
{
GetPriem();
int T,cnt=1,i,j;
long long n,m;
scanf("%d",&T);
while(T--)
{
scanf("%lld",&n);
long long m = 0;
for(int k = 1;k <= n;k++)
{
m += Ans(k);
}
cout<<m<<endl;
}
return 0;
}
题解:
打表找规律。
素因子分解打表计算前n项和判断奇数偶数可以发现如下规律:
只要是2 ^ x,a ^ 2,2 * a ^ 2…只有这种数的因子和是奇数。所以,我们直接去重即可。
但是这些直接去重我们会发现减去的这些值有重复的,所以我们要判断下。
i (代表x||a): 0 1 2 3 4 5 6 7 8 9 …
2^x: 1 2 4 8 16 32 64 128 …
a^2: 0 1 4 9 16 25 36 49 64 …
2*a^2: 0 2 8 18 32 50 72 …
我们可以发现2x里面有的数,a2和2*a^2里面都有。
加下划线的字一一对应,加粗的字一一对应。
①2 ^ x和a ^ 2, 当x为偶数时二者出现重复。
②2 ^ x和2*a ^ 2,当x为奇数时,二者出现重复。
所以不需要考虑2 ^ x的个数,直接用n减去a ^ 2和2*a^2的个数就是我们要的结果。
易知:a ^ 2的个数=sqrt(n),2*a^2的个数=sqrt(n/2)。
那么为什么会是这样呢?给出推导过程:
n=p1 ^ e1p2 ^ e2…,则f(n)=(p1 ^ (e1+1)-1)/(p1-1))(p2^(e2+1)-1)/(p2-1))…
且(p1 ^ (e1+1)-1)/(p1-1))=p1 ^ 0+p1 ^ 1…+p1 ^ e1;
要使得f(n)为奇数,则(p1 ^ (e1+1)-1)/(p1-1)到(pn^(en+1)-1)/(pn-1)都要为奇数;
因为奇数 * 奇数=奇数,奇数 * 偶数=偶数;
1)当p=2时,2^(e+1)-1,一定为奇数;
2)当p!=2时,则p为奇数(因为p是素因子),则当e为偶数时(p^(e+1)-1)/(p-1)为奇数。
经转化我们可以发现,26=82,211=2*322。也就是平方数和2倍的平方数。
则需要统计1到n中的平方数个数和2倍的平方数的个数,得到的为1到n中f(n)为奇数的个数。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int main()
{
int t;
scanf("%d",&t);
for(int kase=1;kase<=t;kase++)
{
LL n;
scanf("%lld",&n);
LL num1=(LL)sqrt((double)n);
LL num2=(LL)sqrt((double)n/2.0);
printf("Case %d: %lld\n",kase,n-num1-num2);
}
return 0;
}