首页 > 其他分享 >【XSY3473】Frog(min25筛)

【XSY3473】Frog(min25筛)

时间:2022-10-30 12:35:32浏览次数:106  
标签:frac int min25 XSY3473 Frog leq sqrt sigma sum

一些记号:

  • 记 \(\mathbb{P}\) 为质数集,\(p_i\) 表示第 \(i\) 个质数。
  • 记 \(\operatorname{lpf}(x)\) 表示 \(x\) 的最小质因数为第几个质数。
  • 特别地,令 \(\operatorname{lpf}(1)=\infty\)。

设 \(c_i\) 表示 \(p_i\) 在 \(m!\) 中的次数,注意到当 \(p_i>\sqrt m\) 时,\(c_i=\lfloor\dfrac{m}{p_i}\rfloor\),所以 \(c_i\) 的取值只有 \(O(\sqrt m)\) 种,而且 \(c_i\) 单调不降。

设 \(F(i,n)\) 表示不考虑前 \(i\) 个质数时的答案,即:

\[F(i,n)=\sum_{x=1}^n \sum_{d|m!}[\operatorname{lpf}(xd)>i]\sigma_0(xd) \]

注意 \(xd=1\) 的情况也会被算入。

考虑递推到 \(F(i-1,n)\),考虑 \(p_i\) 分别在 \(x\) 和 \(d\) 中出现的次数:

\[\begin{aligned} F(i-1,n)&=\sum_{k\geq 0,p_i^k\leq n}\sum_{0\leq j\leq c_i}(k+j+1) F(i,\lfloor\frac{n}{p_i^k}\rfloor)\\ &=\sum_{k\geq 0,p_i^k\leq n}\frac{1}{2}(c_i+1)(c_i+2k+2)F(i,\lfloor\frac{n}{p_i^k}\rfloor) \end{aligned} \]

如果我们能处理出 \(p_{i+1}^2>n\) 时的边界情况,这个递推的时间复杂度就和 min25 筛是一样的了。

当 \(p_{i+1}^2>n\) 时,直接考虑定义式,\(F(i,n)\) 即为:

\[\begin{aligned} F(i,n)&=\sum_{d|m!}[\operatorname{lpf}(d)>i]\sigma_0(d)+\sum_{j>i,p_j\leq n}\sum_{d|m!}[\operatorname{lpf}(d)>i]\sigma_0(p_jd) \end{aligned} \]

我们先考虑一个子问题 \(\sum\limits_{d|T}\sigma_0(d)\),其中设 \(T=\prod\limits_i p_i^{t_i}\)。

相当于对每一个质因数 \(p_i\) 选一个 \(t'_i\leq t_i\) 以确定 \(d\),然后这个 \(d\) 的贡献是 \(\prod\limits_i (1+t_i')\)。于是:

\[\begin{aligned} \sum\limits_{d|T}\sigma_0(d)&=\prod_{i}\left(\sum_{t_i'=0}^{t_i}(1+t_i')\right)\\ &=\prod_i \frac{1}{2}(t_i+1)(t_i+2) \end{aligned} \]

然后再考虑 \(\sum\limits_{d|T}\sigma_0(p_jd)\):

\[\begin{aligned} \sum_{d|T}\sigma_0(p_jd)&=\sum_{d|(p_jT)}\sigma_0(d)-\sum_{d|(T/p_j^{t_j})}\sigma_0(d)\\ &=\sum_{d|T}\sigma_0(d)\frac{\frac{1}{2}(t_j+2)(t_j+3)-1}{\frac{1}{2}(t_j+1)(t_j+2)}\\ \end{aligned} \]

再看回原式,\(\sum\limits_{d|m!}[\operatorname{lpf}(d)>i]\sigma_0(p_jd)\) 其实可以转化成 \(\sum\limits_{d|(m!/\prod_{k\leq i}p_k^{c_k})}\sigma_0(p_jd)\),于是有:

\[\begin{aligned} F(i,n)&=\sum_{d|m!}[\operatorname{lpf}(d)>i]\sigma_0(d)+\sum_{j>i,p_j\leq n}\sum_{d|m!}[\operatorname{lpf}(d)>i]\sigma_0(p_jd)\\ &=\sum\limits_{d|(m!/\prod_{k\leq i}p_k^{c_k})}\sigma_0(d)+\sum_{j>i,p_j\leq n}\sum\limits_{d|(m!/\prod_{k\leq i}p_k^{c_k})}\sigma_0(p_jd)\\ &=\sum\limits_{d|(m!/\prod_{k\leq i}p_k^{c_k})}\sigma_0(d)+\sum_{j>i,p_j\leq n}\sum_{d|(m!/\prod_{k\leq i}p_k^{c_k})}\sigma_0(d)\frac{\frac{1}{2}(c_j+2)(c_j+3)-1}{\frac{1}{2}(c_j+1)(c_j+2)}\\ &=\left(\prod_{j>i}\frac{1}{2}(c_i+1)(c_i+2)\right)\left(1+\sum_{j>i,p_j\leq n}\frac{\frac{1}{2}(c_j+2)(c_j+3)-1}{\frac{1}{2}(c_j+1)(c_j+2)}\right) \end{aligned} \]

相当于我在数轴上有 \(O(\sqrt m)\) 个关键点,关键点之间的质数的 \(c\) 都相等,我在数轴上还有 \(O(\sqrt n)\) 个关键点用于询问,于是我们把这 \(O(\sqrt n)+O(\sqrt m)\) 个关键点混在一起用 min25 筛出来它们的素数个数即可。

有关 min25 筛复杂度的证明:

考虑 \(F(i,j)\) 的状态数,第二维的取值为 \(n,\lfloor\frac{n}{2}\rfloor,\cdots,\lfloor\frac{n}{\sqrt n}\rfloor,\sqrt n,\cdots,1\) 共 \(O(\sqrt n)\) 种(整除分块),第一维的取值范围是 \(O(\pi(\sqrt j))\),于是共有状态数:

\[\begin{aligned} &\sum_{i=1}^{\sqrt n}O(\pi(\sqrt i))+\sum_{i=1}^{\sqrt n}O(\pi(\sqrt{\frac{n}{i}}))\\ \approx&\sum_{i=1}^{\sqrt n}O\!\left(\frac{\sqrt i}{\ln \sqrt i}\right)+\sum_{i=1}^{\sqrt n}O\!\left(\frac{\sqrt{\frac{n}{i}}}{\ln \sqrt{\frac{n}{i}}}\right)\\ \approx&O\left(\int_1^{\sqrt n}\frac{\sqrt x}{\ln \sqrt x}\text{ d}x+\int_{1}^{\sqrt n}\frac{\sqrt{\frac{n}{x}}}{\ln \sqrt{\frac{n}{x}}}\text{ d}x\right)\\ \approx&O\left(\frac{n^{\frac{3}{4}}}{\ln n}\right) \end{aligned} \]

转移时的复杂度忽略,否则太难分析了(

所以你可以把复杂度当成 \(O(n^{\frac{3}{4}})\)。

写代码时写 id 那一段时竟然绕着绕着给自己绕晕了,后来发现只需要记住一件事:id 只是一种给关键点的编码方式,所以你只需要找到一种编码方式保证不会存在两个关键点编号相同即可。

数论题代码果然及其难写,所以代码也写得及其丑,跑得也及其慢。看啥时候有空规范一下自己数论题的码风(

#include<bits/stdc++.h>

#define N 100010
#define ll long long
#define LNF 0x7fffffffffffffff

using namespace std;

namespace modular
{
	const int mod=323232323,inv2=(mod+1)/2;
	inline int add(int x,int y){return x+y>=mod?x+y-mod:x+y;}
	inline int dec(int x,int y){return x-y<0?x-y+mod:x-y;}
	inline int mul(int x,int y){return 1ll*x*y%mod;}
	inline void Add(int &x,int y){x=x+y>=mod?x+y-mod:x+y;}
	inline void Dec(int &x,int y){x=x-y<0?x-y+mod:x-y;}
	inline void Mul(int &x,int y){x=1ll*x*y%mod;}
}using namespace modular;

inline int poww(int a,int b)
{
	int ans=1;
	while(b)
	{
		if(b&1) ans=mul(ans,a);
		a=mul(a,a);
		b>>=1;
	}
	return ans;
}

inline ll read()
{
	ll x=0;
	int f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9')
	{
		if(ch=='-') f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')
	{
		x=(x<<1)+(x<<3)+(ch^'0');
		ch=getchar();
	}
	return x*f;
}

int tot;
int cnt,prime[N];
bool notprime[N];
ll n,m,sn,sm;
ll kp[N*5];

namespace ID
{
	int idn1[N],idn2[N],idm1[N],idm2[N],idmm[N];
	int &id(ll x)
	{
		if(x<=n&&x==n/(n/x)) return x<=sn?idn1[x]:idn2[n/x];
		if(x<=m&&x==m/(m/x)) return x<=sm?idm1[x]:idm2[m/x];
		return idmm[x];
	}
}using ID::id;

int is1[N],is2[N];

ll get(ll p)
{
	ll x=m,ans=0;
	while(x)
	{
		x/=p;
		ans+=x;
	}
	return ans;
}

ll c[N];

void init()
{
	const int nn=100000;
	is1[0]=1;
	for(int i=2;i<=nn;i++)
	{
		if(!notprime[i])
		{
			prime[++cnt]=i;
			c[cnt]=get(i);
			is1[cnt]=mul(is1[cnt-1],poww(mul(inv2,mul((c[cnt]+1)%mod,(c[cnt]+2)%mod)),mod-2));
			int a=dec(mul(inv2,mul((c[cnt]+2)%mod,(c[cnt]+3)%mod)),1);
			int b=mul(inv2,mul((c[cnt]+1)%mod,(c[cnt]+2)%mod));
			is2[cnt]=add(is2[cnt-1],mul(a,poww(b,mod-2)));
		}
		for(int j=1;j<=cnt&&i*prime[j]<=nn;j++)
		{
			notprime[i*prime[j]]=1;
			if(!(i%prime[j])) break;
		}
	}
}

ll g[N*5];

void work1()
{
	for(int i=1;i<=tot;i++) g[i]=kp[i]-1;
	for(int i=1;i<=cnt;i++)
	{
		ll p=prime[i],p2=p*p;
		for(int j=tot;p2<=kp[j];j--)
			g[j]-=g[id(kp[j]/p)]-(i-1);
	}
}

int f[N*5];
int sum1[N*5],sum2[N*5];
bool vis[N*5];

int bound(int i,ll n)
{
	int a=mul(sum1[tot],is1[i]);
	int b=prime[i]<=n?dec(sum2[id(n)],is2[i]):0;
	return mul(a,add(b,1));
}

void work2()
{
	for(int i=cnt;i>=1;i--)
	{
		ll p=prime[i],p2=p*p,p22=(i==cnt?LNF:1ll*prime[i+1]*prime[i+1]);
		for(int j=tot;p2<=kp[j];j--)
		{
			if(!vis[j]) f[j]=bound(i,kp[j]),vis[j]=1;
			Mul(f[j],mul(inv2,mul((c[i]+1)%mod,(c[i]+2)%mod)));
			ll pk=p;
			for(int k=1;pk<=kp[j];k++,pk*=p)
			{
				int coef=mul(inv2,mul((c[i]+1)%mod,(c[i]+2*k+2)%mod));
				ll v=kp[j]/pk;
				if(p22>v) Add(f[j],mul(coef,bound(i,v)));
				else Add(f[j],mul(coef,f[id(v)]));
			}
		}
	}
}

int main()
{
	n=read(),m=read();
	sn=sqrt(n),sm=sqrt(m);
	init();
	for(ll l=1,r;l<=n;l=r+1)
		kp[++tot]=r=(n/(n/l));
	for(ll l=1,r;l<=m;l=r+1)
		kp[++tot]=r=(m/(m/l));
	for(ll i=1;i*i<=m;i++)
		kp[++tot]=i;
	sort(kp+1,kp+tot+1);
	tot=unique(kp+1,kp+tot+1)-kp-1;
	for(int i=1;i<=tot;i++) id(kp[i])=i;
	work1();
	sum1[1]=1;
	//kp[i-1]+1 ~ kp[i]
	for(int i=2;i<=tot;i++)
	{
		ll np=g[i]-g[i-1];
		ll c=get(kp[i]);
		sum1[i]=mul(sum1[i-1],poww(mul(inv2,mul((c+1)%mod,(c+2)%mod)),np));
		int a=dec(mul(inv2,mul((c+2)%mod,(c+3)%mod)),1);
		int b=mul(inv2,mul((c+1)%mod,(c+2)%mod));
		sum2[i]=add(sum2[i-1],mul(np,mul(a,poww(b,mod-2))));
	}
	work2();
	printf("%d\n",f[id(n)]);
	return 0;
}
/*
10 3
*/
/*
323232323 23
*/

标签:frac,int,min25,XSY3473,Frog,leq,sqrt,sigma,sum
From: https://www.cnblogs.com/ez-lcw/p/16840982.html

相关文章

  • JFrog Xray 与 Amazon Security Hub 集成
    SecOps需要警惕,但也需要可见性。借助JFrog最新的Xray与AmazonSecurityHub集成,可以帮助您确保发现的漏洞不仅被发现,而且可以迅速采取行动。AmazonSecurityHub ......
  • LeetCode 1419. Minimum Number of Frogs Croaking
    原题链接在这里:https://leetcode.com/problems/minimum-number-of-frogs-croaking/题目:Youaregiventhestring croakOfFrogs,whichrepresentsacombinationofth......
  • 题解 [POI2010]ZAB-Frog
    很厉害的题。倍增和单调队列。这是zpl新手向算法第二弹,第一弹可以看小挖的核燃料填充我会尽量讲的比较细致。同第一弹,尽量配合代码食用。这道题的题目描述写的不是......
  • GYM100851 F - Froggy Ford(最短路铜牌题)
    题意:​ 现在有一条河,河中有n个石头,你需要从河的一端到河的另一端。现在你有一次机会在任意位置放置一个石头,请问石头放在哪里可以使过河的最长路径最短。请输出放置的石头......
  • gym-103708F Froginald the frog
    Froginaldthefrog矩阵快速幂如果没有分隔的话,这就是一个矩阵快速幂求斐波那契的问题因为有分隔,因此考虑他们分成若干个块,每个块的方案数之积就是答案,显然分隔的长度如......
  • 2022杭电多校 第9场 1005 Leapfrogger (期望)
    可以说官方题解除了恶心其他人和告诉你这题不难之外没有任何作用。考虑期望的线性性,可以将每一个跳蛙的每一个亡语单独考虑。令\(f_n\)代表剩余\(n\)个随从,其中有一个是......
  • CodeForces-1601B Frog Traveler
    FrogTravelerdp+bfs感觉又像搜索从后往前进行状态转移,像\(bfs\)一样保证当前搜索的是消耗次数最少的状态转移因为是一个连续的区间,因此考虑当前能上升到的最大距......