2018ACM/ICPC南京站网络赛J Sum

题目链接

大意是定义f(x)为满足x==a*b且a和b均不能被除1以外的平方数整除的数对(a,b)的个数,给定n,输出x从1到n的f(x)的和。

比赛中这道题从看题,到写完,再到写个暴力对拍小数据也只花了二十五分钟而已,然后一发入魂。。。(虽然这题后就陷入了漫长的卡题)

我的解题思路的产生:首先看到数据范围2e7,虽然查询很少,但一般这个范围会让我联想到线性筛;其次,大致看下样例就能知道素数x的f(x)=2,而f(x)为0的都是x至少含有一个素因子大于等于3次的。

在线性筛的过程中,如果x是素数,对应的f(x)值赋值为2;
在筛素数倍数(即x=i*prime[j])的时候,如果i不是prime[j]的倍数,那么有f(x)=2*f(i),因为多出来的素因子prime[j]可以放a也可以放b,所以是在原来的基础上乘2;
如果i是 prime[j]^2 的倍数,则x=i*prime[j]至少含有因子 prime[j]^3,那么不论这个因子怎么分配,均会使得a,b其中一个数含有因子prime[j]^2,因此此时有f(x)=0;
如果i是 prime[j]的倍数,则x=i*prime[j]恰好是prime[j]^2的倍数,那么只能将prime[j]分别放在a和b中,和不放的数目是一样的,因此f(x)=f(i)。

筛完求个前缀和,O(1)查询即可。

代码如下:

#include<bits/stdc++.h>
using namespace std;
#define For(i,a,b) for(int i=a;i<=b;i++)
const int N = 2e7+5;
const int mod=1e9+7;
bool notprime[N];
int cnt,prime[1300000];
int ans[N];
void init(){
	notprime[1]=1;ans[1]=1;
	For(i,2,N-1){
		if(!notprime[i]){
			prime[cnt++]=i;ans[i]=2;
		}
		for(int j=0;j<cnt&&i*prime[j]<N;j++){
			notprime[i*prime[j]]=1;
			if(i%prime[j]==0){
				if(i/prime[j]%prime[j]==0)
				ans[i*prime[j]]=0;
				else
				ans[i*prime[j]]=ans[i/prime[j]];
				break;
			}
			ans[i*prime[j]]=2*ans[i];
		}
	}
	For(i,1,N-1) ans[i]+=ans[i-1];
}
int t,n;
int main(){
	init();
	scanf("%d",&t);
	while(t--){
		scanf("%d",&n);
		printf("%d\n",ans[n]);
	}
	return 0;
}

时间:比赛中396ms,赛后443ms。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值