HDU6588 Function 公式推导 积函线筛
先附一个积性函数线筛的link
https://www.cnblogs.com/zhoushuyu/p/8275530.html 讲的巨好
这个公式分为两部分求
一部分是
这里的n指小于等于的最大值
这个咋来的呢 好像是归纳整理推导来的
另一部分呢,是就多出来的部分
对于第一部分
显然就是
中间的那个可以筛出来
在求个前缀和预处理完成
设多出来的长度为m
多出来的部分就是
这个是积性函数 可以线筛出来
然后问题就也许可能大概解决了
时间复杂度
标程好像
离奇卡过
后来又发现
这东西这不是的狄利克雷卷积嘛
然后又线筛去掉
搞定
自己踩得坑:
①关于 int 和long long 问题 能用 int 坚决不用long long
②
一定要开long double 否则精度不够会WA
③积函线筛要牢记
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef __int128 lll;
//typedef long long lll;
const int maxn=1e7+5;
const int mod=998244353;
template <class T>
void read(T &x)
{
static char ch;
static bool neg;
for(ch=neg=0; ch<'0' || '9'<ch; neg|=ch=='-',ch=getchar());
for(x=0; '0'<=ch && ch<='9'; (x*=10)+=ch-'0',ch=getchar());
x=neg?-x:x;
}
inline void addx(int&x,int y)
{
(x+=y)<mod?:x-=mod;
}
inline int mul(int x,int y)
{
return 1LL*(x)*y%mod;
}
inline int add(int x,int y)
{
return (x+=y)<mod?x:x-mod;
}
bool vis[maxn];
int phi[maxn];
int cnt,prim[maxn];
int a[maxn];
int sum[maxn];
int f[maxn];
int low[maxn];
void init()
{
phi[1]=1;
for(int i=2; i<maxn; i++)
{
if(!vis[i])
{
prim[++cnt]=i;
phi[i]=i-1;
}
for(int j=1; j<=cnt&&prim[j]*i<maxn; j++)
{
vis[i*prim[j]]=1;
if(i%prim[j]==0)
{
phi[i*prim[j]]=phi[i]*prim[j];
break;
}
else
{
phi[i*prim[j]]=phi[i]*(prim[j]-1);
}
}
}
}
void sieve(int n,int m)
{
int tot=0;
memset(low,0,sizeof(low));
memset(prim,0,sizeof(prim));
memset(vis,0,sizeof(vis));
memset(f,0,sizeof(f));
vis[1]=low[1]=1;
f[1]=1;
for (ll i=2; i<=m; i++)
{
if (!vis[i])
{
low[i]=prim[++tot]=i;
if(n%i==0)
f[i]=i;
else
f[i]=1;
}
for (ll j=1; j<=tot&&i*prim[j]<=m; j++)
{
vis[i*prim[j]]=1;
if (i%prim[j]==0)
{
low[i*prim[j]]=low[i]*prim[j];
if (low[i]==i)
{
if(n%(i*prim[j])==0)
{
f[i*prim[j]]=(i*prim[j]);
}
else
f[i*prim[j]]=f[i];
}
else
f[i*prim[j]]=f[i/low[i]]*f[low[i]*prim[j]];
break;
}
low[i*prim[j]]=prim[j];
f[i*prim[j]]=f[i]*f[prim[j]];
}
}
}
void solve()
{
int tot=0;
memset(low,0,sizeof(low));
memset(prim,0,sizeof(prim));
memset(vis,0,sizeof(vis));
memset(a,0,sizeof(a));
vis[1]=low[1]=1;
a[1]=1;
for (ll i=2; i<maxn; i++)
{
if (!vis[i])
{
low[i]=prim[++tot]=i;
a[i]=2*i-1;
}
for (ll j=1; j<=tot&&i*prim[j]<maxn; j++)
{
vis[i*prim[j]]=1;
if (i%prim[j]==0)
{
low[i*prim[j]]=low[i]*prim[j];
if (low[i]==i)
{
a[i*prim[j]]=prim[j]*a[i]+phi[i*prim[j]];
}
else
a[i*prim[j]]=a[i/low[i]]*a[low[i]*prim[j]];
break;
}
low[i*prim[j]]=prim[j];
a[i*prim[j]]=a[i]*a[prim[j]];
}
}
for(int i=1; i<maxn; i++)
{
sum[i]=add(sum[i-1]+i,mul(3*i+3,a[i]));
}
}
void solve2()
{
for(int i=1; i<maxn; i++)
{
for(int j=1; i*j<maxn; j++)
{
addx(a[i*j],j*phi[i]);
}
}
for(int i=1; i<maxn; i++)
{
sum[i]=add(sum[i-1]+i,mul(3*i+3,a[i]));
}
}
int main()
{
init();
solve();
int t;
read(t);
lll n;
for(int cas=0; cas<t; cas++)
{
read(n);
int pos=pow(n+0.9,(long double)1.0/3);
int ans=sum[pos-1];
ll c=n-(lll)pos*pos*pos;
addx(ans,mul((c/pos),a[pos]));
c%=(pos);
sieve(pos,c);
for(int i=1; i<=c; i++)
{
addx(ans,f[i]);
}
addx(ans,pos);
printf("%d\n",ans);
}
return 0;
}