1. 程式人生 > >5297 十分優(lie)質的容斥

5297 十分優(lie)質的容斥

如果做過簡化版,看到這道題第一反應就是二分答案,找最小的N滿足他前面的數(包含他自己)刪去可以開1到r次方的數之後只剩下n個。但是這道題用二分答案會TLE(不知道寫的好會不會,但是我會)。且找N他前面的數(包含他自己)刪去可以開1到r次方的數之後剩下多少個的方法也很重要。

優(lie)質的找n他前面的數(包含他自己)刪去可以開1到r次方的數之後剩下多少個的方法如下:(由於是蒟蒻,有錯請大佬指正)

舉個例子 n=70 r=6;

記S[i]為\sqrt[i]{x}<=n\sqrt[i]{x}為一個整數的x的集合

故S[2]={1,4,9,16,25,36,49,64}

S[3]={1,8,27,64}

S[5]={1,32}

S[6]={1,64}

ans的補集={1,4,8,9,16,25,27,32,36,49,64}

一共11個(即為1+cnt[S[2]]-1+cnt[S[3]-1+cnt[S[5]]-1-(cnt[S[6]]-1))注意這裡是在計算ans的補集。

cnt(ans)=N-cnt[ans的補集];

具體流程講解:

由於1十分特殊,故在容斥時將1排除在外。最後加上就可以了。

求cnt[S[i]]可以用pow函式 如cnt[S[i]]=pow(1.0*x+0.5,1.0/i)-1。(+0.5是為了精度,-1是篩掉1)

先刪去所有小於等於N的質數次方數。那麼64會重複,為什麼呢,因為64=(2^3)^2=(2^2)^3,故會被算到兩遍。(也就是S[2]與S[3]都包含S[6])

再加上有兩種所有小於等於N的質陣列成的數的次方數,減去有三種所有小於等於N的質陣列成的數的次方數(注意此處組成是每種質數只有一個)。就和普通的容斥一樣。

優(lie)質的就是在處理小於等於r的質數和小於等於63的有這些質陣列成的數。(long long 的上限2^64-1)

首先處理質數要都取他的相反值。

開始佇列為空,之後每放入一個質數都和佇列裡的數乘一下(該層新加如的數除外),所得數加入佇列。

這個過程和DP有點相似。(處理出的數有正有負,正的說明是有偶數個質陣列成,負的說明是奇數個質陣列成)。再容斥即可。

AC程式碼:

#include<cstdio>
#include<cmath>
int r;
bool mark[105];
int id,prime[105],num[105],nnum;
void Init(){//篩出67以內的質數
	for(int i=2;i<=67;i++){
		if(mark[i])continue;
		prime[++id]=-i;//質數直接篩成負數,在後面不用判個數 
		for(int j=i+i;j<=67;j+=i)mark[j]=1;
	}
}
void change(){
	nnum=0;
	for(int i=1;-prime[i]<=r;i++){
		int cnt=nnum;
		for(int j=1;j<=cnt;j++)if(abs(num[j]*prime[i])<=63)num[++nnum]=num[j]*prime[i];//注意邊界 
		//類似DP的處理出63以內的質數以及由質陣列成的數(每個由參與組成的每種質數個數不超過一個) 
		num[++nnum]=prime[i];
	}
}
long long get_ans(long long x){
	long long ans=x;
	for(int i=1;i<=nnum;i++){
		long long tmp=1ll*pow(1.0*x+0.5,1.0/(1.0*abs(num[i])))-1;//x加0.5是為了精度, tmp等於有多少個數的num[i]次方小於等於x,減1是為了排除1 
		if(num[i]<0)ans-=tmp;//由奇數個質陣列成
		else ans+=tmp;//由偶數個質數構成 
	}
	return ans-1;//1可以被開任意次方 
}
void solve(long long n,int r){
	change();
	long long ans=n;
	while(1) {//神奇的列舉方式 
		long long res=get_ans(ans);
		if(res==n)break;
		ans+=n-res;
	}
	printf("%lld\n",ans);
}
int main(){
	int T;
	Init();
	scanf("%d",&T);
	while(T--){
		long long n;
		scanf("%lld%d",&n,&r);
		solve(n,r);
	}
	return 0;
}