P9238 [蓝桥杯 2023 省 A] 翻转硬币

题目传送门

受益良多啊……

f(i) 表示第 i 枚硬币是否需要被翻转,以下所有运算均在模 2 意义下进行。

初始化 f(1)=1,递推式有 f(i)=di,dif(d),答案即求 i=1nf(i)

观察发现 dif(d)=2f(i)=[i=1],写成卷积形式就是 fI=ϵ,反演一下得 f=μ

μ(i)=1 时,可令 f(i)1,因此答案即求 i=1nμ2(i)

来到本题一个重要的 Trick —— μ2 的前缀和计算

考虑 μ2(i) 的实际意义,即 i 是否含有平方因子。那么将 i 质因数分解得 pici,令 P=pici/2,那么 μ2(i)=1P=1。因此有 μ2(i)=[P=1]=dPμ(d)=d2iμ(d)

所以

i=1nμ2(i)=i=1nμ(i)ni2

那么问题就涉及到了高次整除分块。对 ni2 整除分块,r=nni2,时间复杂度 O(n13)

预处理 O(n25) 的前缀和可以做到复杂度 O(n25),证明太难不会。

#include<bits/stdc++.h>
#define LL long long
using namespace std;

const int N=1.6e7+10;

LL n,lim,ans;
int v[N],prime[N],mu[N],sum[N],tot;
unordered_map <LL,LL> tmp;

void prework()
{
	mu[1]=1;
	for(int i=2; i<=lim; i++)
	{
		if(!v[i])
		{
			v[i]=i;
			prime[++tot]=i;
			mu[i]=-1;
		}
		for(int j=1; j<=tot; j++)
		{
			if(prime[j]>v[i] || prime[j]>lim/i)
				break;
			v[i*prime[j]]=prime[j];
			if(i%prime[j]==0)
				break;
			mu[i*prime[j]]=-mu[i];
		}
	}
	for(int i=1; i<=lim; i++)
		sum[i]=sum[i-1]+mu[i];
}

LL query(LL n)
{
	if(n<=lim)
		return (LL)sum[n];
	auto it=tmp.find(n);
	if(it!=tmp.end())
		return it->second;
	LL res=1;
	for(LL l=2,r; l<=n; l=r+1)
	{
		r=n/(n/l);
		res-=(r-l+1)*query(n/l);
	}
	return tmp[n]=res;
}

signed main()
{
	scanf("%lld",&n);

	lim=powl(n,2.0/5)+10;
	prework();

	for(LL l=1,r; l<=sqrtl(n); l=r+1)
	{
		r=sqrtl(n/(n/(l*l)));
		ans+=(query(r)-query(l-1))*(n/(l*l));
	}

	printf("%lld\n",ans);

	return 0;
}
posted @   xishanmeigao  阅读(74)  评论(0编辑  收藏  举报
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?
点击右上角即可分享
微信分享提示