HDU 5317 RGCDQ

题意:记F[i]为i的质因子种数,求 max l < = i < j < = r g c d ( F [ i ] , F [ j ] ) \max_{l<=i<j<=r} {gcd(F[i],F[j])}

首先可以想到F[i]的值一定很小,由题知区间范围最大是100W,Win+R敲入calc打开计算器算一下知道F[i]的值最大为8。
2 3 5 7 11 13 17 19 = 9699690 > 100 W 2*3*5*7*11*13*17*19=9699690>100W

题目要计算的是某个区间的gcd值,且我们最多区间内元素最多只有8种,我们可以预处理前缀数组precnt[i][num],表示从1~i中F的值为num的元素个数,然后 O ( 1 ) O(1) 地计算出任意区间[l,r]的8种元素对应的个数。然后对存在的元素进行相互gcd取最大值就可以了(记得如果某个元素存在两个以上要和自身做一个gcd)。

至此问题已经解决,但是这样子会进行很多的重复计算,共100W次查询,每次计算答案计算量为 O ( 8 7 / 2 = 28 ) O(8*7/2=28) 次。

由于总共的F[i]的集合很少,最多是2^8=256个,每一种集合对应的答案都是固定的,所以我们可以使用状压的办法记录下每种集合对应的答案,ans[s]表示s状态对应的答案。(!!!别给忘记了还要另外考虑上与自身计算gcd的8个),于是 O ( 1 + 8 = 9 ) O(1+8=9) 得到答案。

未状压优化代码(2184ms)

#include<bits/stdc++.h>
#define rep(i,l,r) for(int (i)=(l);(i)<=(r);(i)++)
#define per(i,l,r) for(int (i)=(r);(i)>=(l);(i)--)
using namespace std;
const int N=1e6,maxS=1<<9;
int t,l,r,f[N+100],ans[maxS],precnt[N+100][9];
//f[i]表示i这个数的不同质因子的个数
//ans[s]表示s这个状态压缩后的状态对应的答案个数
//precnt[i][num]表示前i个数中f[i]的值为num的个数,对个数做的前缀和。 
int prime[N+100],tot;
bool isprime[N+100];
int gcd(int a,int b){
	return b==0?a:gcd(b,a%b);
}
void Eratos_Prime(){
	memset(isprime,true,sizeof(isprime));
	rep(i,2,N){
		if(isprime[i]==false) continue;
		prime[++tot]=i;
		for(int j=i;j<=N/i;j++)//这里要写成除法不然会爆int 
			isprime[i*j]=false;
	}
}
void Preprocess1(){
	//预处理f数组 
	rep(i,1,tot)
		for(int j=1;prime[i]*j<=N;j++)
			f[prime[i]*j]++;
	//预处理前缀和 
	rep(i,2,N){
		rep(j,0,8) precnt[i][j]=precnt[i-1][j];
		precnt[i][f[i]]++;
	}
}
int calc(int cnt[]){
	int ans=0;
	rep(i,0,8){
		if(cnt[i]==0) continue;
		if(cnt[i]>=2) ans=max(ans,i);
		rep(j,i+1,8){
			if(cnt[j]==0) continue;
			ans=max(ans,gcd(i,j));
		}
	}
	return ans; 
}
int main(){
	ios::sync_with_stdio(false);
	cin>>t;
	Eratos_Prime();//埃筛
	Preprocess1();//预处理出f[i]
	while(t--){
		cin>>l>>r;
		int nowcnt[9];
		rep(i,0,8) nowcnt[i]=precnt[r][i]-precnt[l-1][i];
		cout<<calc(nowcnt)<<endl;
	}
	return 0;
}

状压优化代码(1887MS…没快多少)

#include<bits/stdc++.h>
#define rep(i,l,r) for(int (i)=(l);(i)<=(r);(i)++)
#define per(i,l,r) for(int (i)=(r);(i)>=(l);(i)--)
using namespace std;
const int N=1e6,maxS=1<<9;
int t,l,r,f[N+100],ans[maxS],precnt[N+100][9];
//f[i]±íʾiÕâ¸öÊýµÄ²»Í¬ÖÊÒò×ӵĸöÊý
//ans[s]±íʾsÕâ¸ö״̬ѹËõºóµÄ״̬¶ÔÓ¦µÄ´ð°¸¸öÊý
//precnt[i][num]±íʾǰi¸öÊýÖÐf[i]µÄֵΪnumµÄ¸öÊý£¬¶Ô¸öÊý×öµÄǰ׺ºÍ¡£ 
int prime[N+100],tot;
bool isprime[N+100];
int gcd(int a,int b){
	return b==0?a:gcd(b,a%b);
}
void Eratos_Prime(){
	memset(isprime,true,sizeof(isprime));
	rep(i,2,N){
		if(isprime[i]==false) continue;
		prime[++tot]=i;
		for(int j=i;j<=N/i;j++)//ÕâÀïҪд³É³ý·¨²»È»»á±¬int 
			isprime[i*j]=false;
	}
}
void Preprocess1(){
	//Ô¤´¦ÀífÊý×é 
	rep(i,1,tot)
		for(int j=1;prime[i]*j<=N;j++)
			f[prime[i]*j]++;
	//Ô¤´¦Àíǰ׺ºÍ 
	rep(i,2,N){
		rep(j,0,8) precnt[i][j]=precnt[i-1][j];
		precnt[i][f[i]]++;
	}
}
void Preprocess2(){
	rep(s,0,maxS-1){
		rep(i,0,8){
			if((s&(1<<i))==0) continue;
			rep(j,i+1,8){
				if((s&(1<<j))==0) continue;
				ans[s]=max(ans[s],gcd(i,j));
			}
		}
	}
}
int main(){
	ios::sync_with_stdio(false);
	cin>>t;
	Eratos_Prime();//°£É¸
	Preprocess1();//Ô¤´¦Àí³öf[]ÓëPrecnt[][]. 
	Preprocess2();//Ô¤´¦Àí³öans[].
	while(t--){
		cin>>l>>r;
		int nows=0,nowans=0;
		rep(i,0,8){
			int tmpcnt=precnt[r][i]-precnt[l-1][i];
			if(tmpcnt==0) continue;
			if(tmpcnt>=2) nowans=max(nowans,i);
			nows|=(1<<i);
		}
		cout<<max(ans[nows],nowans)<<endl;
	}
	return 0;
}
发布了49 篇原创文章 · 获赞 10 · 访问量 9285

猜你喜欢

转载自blog.csdn.net/TengWan_Alunl/article/details/103115494
hdu