【hdu6588】2019多校第一场K题function,反演

题目
枚举gcd,最后化简得 ∑ i = 1 n 3 φ ( x ) ∑ i = 1 ⌊ n x ⌋ [ x ∣ ⌊ x i 3 ⌋ ] \sum^{\sqrt[3]{n}}_{i=1}φ(x)\sum^{\lfloor \frac n x\rfloor}_{i=1}[x|\lfloor\sqrt[3]{xi}\rfloor] i=13n φ(x)i=1xn[x3xi ]
后面那个式子通过考虑x的倍数来解决,即枚举x,2x,3x,…,考虑此时i如何取值,因此可以发现每次i是连续的一段一段取得,区间类似于 [ p 3 x 2 , ( p x + 1 ) 3 − 1 x ] [p^3x^2,\frac {(px+1)^3-1} x] [p3x2,x(px+1)31]
最后可以得到,后面那个sigma就是
( ⌊ n x ⌋ − q 3 x 2 + 1 ) + ( 3 x ⋅ ( 2 p + 1 ) ( p + 1 ) p 6 + 3 ⋅ ( p + 1 ) p 2 + p ) (\lfloor \frac n x\rfloor-q^3x^2+1)+(3x·\frac {(2p+1)(p+1)p}{6}+3·\frac {(p+1)p}{2}+p) (xnq3x2+1)+(3x6(2p+1)(p+1)p+32(p+1)p+p)
其中p是满足 ( p x + 1 ) 3 − 1 x ≤ ⌊ n x ⌋ \frac {(px+1)^3-1} x\le\lfloor\frac n x\rfloor x(px+1)31xn的最大值
q是满足 q 3 x 2 ≤ ⌊ n x ⌋ q^3x^2\le\lfloor\frac n x\rfloor q3x2xn的最大值
且当 p = q p=q p=q时,不计算上面q那部分括号里的值
然后直接做是 O ( T n 3 ) O(T\sqrt[3]n) O(T3n )的,理论(题解上说)可以过,但实际TLE
通过(打表)分析得到p是连续一段,且q只会出现在区间边界处(1个或0个),所以可以分块计算,预处理 φ ( x ) φ(x) φ(x) x ⋅ φ ( x ) x·φ(x) xφ(x)的前缀和,同时用二分计算三次根号,可以在 O ( n 3 + T n 6 log ⁡ n ) O(\sqrt[3]n+T\sqrt[6]n\log n) O(3n +T6n logn)时间内得到答案
最后答案要取模,但全程答案不会超过int128,所以只在最后取模即可
代码:

#include<cstdio>
#include<iostream>
#define LL __int128
#define M 10000005
#define mo 998244353
using namespace std;
//所有用LL定义的类型全改成int128(long long类型不用改,只改宏定义的) 
int prime[M/10],phi[M],sum_phi[M],x_phi[M];
bool vis[M];
LL n;
LL gao(LL id)
{
	return id*(id+1)*(2*id+1)/6;
}
LL pt(LL x)
{
	return x*x*x;
}
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;
}
LL sear(LL x,LL cao)
{
	LL l=1,r=x,mid;
	if (r>cao) r=cao;
	while (l<=r)
	{
		mid=l+r>>1;
		if (mid<=x/mid/mid) l=mid+1;
		else r=mid-1; 
	}
	return l-1;
}
main()
{
	phi[1]=1;
	for (int i=2;i<=M-5;++i)
	{
		if (!vis[i])
			phi[i]=i-1,
			prime[++prime[0]]=i;
		for (int j=1;j<=prime[0]&&prime[j]*i<=M-5;++j)
		{
			vis[prime[j]*i]=1;
			if (i%prime[j])
				phi[i*prime[j]]=phi[i]*(prime[j]-1);
			else
			{
				phi[i*prime[j]]=phi[i]*prime[j];
				break;
			}
		}
	}
	for (int i=1;i<=M-5;++i)
		sum_phi[i]=(sum_phi[i-1]+phi[i])%mo,
		x_phi[i]=(x_phi[i-1]+1LL*i*phi[i]%mo)%mo;
	int T;
	for (scanf("%d",&T);T;--T)
	{
		read(n);//改成__int128读入 
		LL idd,tmp,last;
		int lim=1;
		LL ans=0;
		lim=sear(n,10000000);
		idd=lim;
		for (int x=1;x<=lim;x=last+1)
		{
			tmp=(n/x/x/x);
			idd=sear(tmp,idd);
			last=sear(n/idd/idd/idd,10000000);
			if (last!=x) ans+=3*gao(idd)*(x_phi[last-1]-x_phi[x-1])+(3*(idd+1)*idd/2+idd)*(sum_phi[last-1]-sum_phi[x-1]);
			if (pt(idd*last+1)-1>n/last*last)
				ans+=(3*gao(idd-1)*last+3*(idd-1)*idd/2+idd+(n/last)-idd*idd*idd*last*last)*phi[last];
			else
				ans+=(3*gao(idd)*last+3*(idd+1)*idd/2+idd)*phi[last];
		}
		printf("%d\n",(int)(ans%998244353));
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值