BZOJ 3181: [Coci2012]BROJ 【数据分治(暴力+(二分&&容斥))

根据数据范围猜解法,数据分治!!!【x

好吧……其实是先想到了容斥的,然而容斥姿势不太好果断GG没写,反正觉得容斥的话p肯定不能太大,然后又yy了循环节啥的各种鬼畜东西233333(虽然最后发现根本没什么卵用

然后在考试结束前几分钟被小朋友嘲讽,忽然就想到了怎么写p比较大的,在线性筛的时候,顺手记录每个数的最小质因子,因为p大,所以p的系数应该是很小的,于是直接枚举,如果枚举到的数的最小质因子大于等于p就++cnt,最后cnt==n的时候break

容斥的时候可以用dfs,乘上当前的数如果比n大就直接continue,剪了一堆枝


我应该是写挂了…………反正数据水23333

#include<bits/stdc++.h>
#define INF 1000000000
#define MAXN 2000005
using namespace std;	int n,p;
int tag[MAXN] , prime[MAXN];

void get_prime(int x){
	for(int i=2;i<=x;++i){
		if(!tag[i])	prime[++prime[0]] = i , tag[i] = i;
		for(int j=1;j<=prime[0];++j){
			if(1ll*i*prime[j]>x)	break;
			tag[i*prime[j]] = prime[j];
			if(!(i%prime[j]))	break;
		}
	}
//	for(int i=0;i<=prime[0];++i)	printf("%d\n",prime[i]);
}

int tmp;
void dfs(int x,int pos,int pro,int k){
	if(!pos)	tmp += x/pro *k;
	else{
		dfs(x,pos-1,pro,k);
		if(1ll*pro*prime[pos]<=x)
			dfs(x,pos-1,pro*prime[pos],-k);
	}
}

void sol(){
	get_prime(p);
	int pos = prime[0];
	int l = p*p , r = INF+1;
	while(l^r){
		int mid = (l+r)>>1;
		tmp = 0;
		dfs(mid/p,pos-1,1,1);
		if(tmp<n)	l = mid+1;
		else r = mid;
	}
	printf("%d",l>INF?0:l);
}

int main(){
//	freopen("broj.in","r",stdin);
//	freopen("broj.out","w",stdout);
	
	scanf("%d%d",&n,&p);

	if(n==1)	return printf("%d",p),0;
	
	if(1ll*n*p>INF)	return puts("0"),0;
	
	if(p==2){
		long long ans = 2ll*n;
		printf("%lld",ans>INF?0ll:ans);
		return 0;
	}
	
	if(p>=500){
		get_prime(2000000);
		for(int i=p,j=1;i<=2000000;++i){
			if(tag[i]>=p)	++j;
			if(j==n)
				return printf("%d",1ll*i*p>INF?0:i*p),0;
		}
	}
	else
		sol();
		
	return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值