列表

详情


NC210771. 有用的LCM

描述

题目背景
题面
定义前缀 lcm 为 ,且一个数 x 对其前缀 lcm 有贡献当且仅当
特别的, 1 不视为对其前缀 lcm 有贡献
现在你需要求出 1~ n 内所有对其前缀 lcm 有贡献的数的个数

输入描述

一个数 n  ()

输出描述

一个数 x 表示答案

示例1

输入:

10

输出:

7

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++14(g++5.4) 解法, 执行用时: 821ms, 内存消耗: 24176K, 提交时间: 2020-10-16 19:59:28

#pragma GCC optimize(2)
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#define ll long long 
#define maxn 1000005
using namespace std;

ll n,i,j,k,ans,pri[maxn],mp[maxn],tot,bz[maxn];

void getpri(){
	for(ll i=2;i<maxn;i++){
		if (!bz[i]) pri[++tot]=i,mp[tot]=1ll*i*i;
		for(ll j=1;j<=tot&&i*pri[j]<maxn;j++){
			bz[i*pri[j]]=1;
			if (i%pri[j]==0) break;
		}
	}
}

ll cnt,id1[maxn],id2[maxn]; ll g[maxn],f[maxn];

ll doit(ll n){
	ll i,j,B=sqrt(n);
	for(ll i=1;i<=n;i=j+1){
		j=n/(n/i),g[++cnt]=n/i;
		if (n/i<=B) id1[n/i]=cnt;
		else id2[n/(n/i)]=cnt;
		f[cnt]=g[cnt]-1;
	}
	for(j=1;j<=tot&&mp[j]<=n;j++)
		for(i=1;i<=cnt&&mp[j]<=g[i];i++){
			k=(g[i]/pri[j]<=B)?id1[g[i]/pri[j]]:id2[n/(g[i]/pri[j])];
			f[i]=f[i]-f[k]+j-1;
		}
	return f[1];
}

int main(){
	scanf("%lld",&n),getpri();
	ans=doit(n);
	for(i=1;mp[i]<=n;i++){
		ll x=mp[i];
		while (x<=n) ans++,x*=pri[i];
	}
	printf("%lld",ans);
}

C++11(clang++ 3.9) 解法, 执行用时: 389ms, 内存消耗: 15736K, 提交时间: 2020-10-16 22:57:40

#include<bits/stdc++.h>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
typedef long long ll;
const int N=7e5;
ll i,j,k,n,sqr,p[N],x,ans,m,w[N],g[N],id1[N],id2[N];
bool bz[N];
int main()
{
	scanf("%lld",&n),sqr=sqrt(n);
	fo(i,2,sqr)
	{
		if(!bz[i])
		{
			p[++p[0]]=i;
			for(ll t=n/i;t>=i;t/=i)
			ans++;
		}
		for(j=1;(j==1||i%x)&&i*(x=p[j])<=sqr;j++)
		bz[i*x]=1;
	}
	fo(i,1,n)
	{
		j=n/(w[++m]=n/i);
		w[m]<=sqr?id1[w[m]]=m:id2[n/w[m]]=m;
		g[m]=w[m]-1;
		i=j;
	}
	fo(j,1,p[0])
	fo(i,1,m)
	{
		if(p[j]*p[j]>w[i])
		break;
		k=((x=w[i]/p[j])<=sqr)?id1[x]:id2[n/x];
		g[i]-=g[k]-(j-1);
	}
	printf("%lld",ans+g[1]);
}

上一题