题意:记F[i]为i的质因子种数,求
首先可以想到F[i]的值一定很小,由题知区间范围最大是100W,Win+R敲入calc打开计算器算一下知道F[i]的值最大为8。
(
)
题目要计算的是某个区间的gcd值,且我们最多区间内元素最多只有8种,我们可以预处理前缀数组precnt[i][num],表示从1~i中F的值为num的元素个数,然后 地计算出任意区间[l,r]的8种元素对应的个数。然后对存在的元素进行相互gcd取最大值就可以了(记得如果某个元素存在两个以上要和自身做一个gcd)。
至此问题已经解决,但是这样子会进行很多的重复计算,共100W次查询,每次计算答案计算量为 次。
由于总共的F[i]的集合很少,最多是2^8=256个,每一种集合对应的答案都是固定的,所以我们可以使用状压的办法记录下每种集合对应的答案,ans[s]表示s状态对应的答案。(!!!别给忘记了还要另外考虑上与自身计算gcd的8个),于是 得到答案。
未状压优化代码(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;
}