您的位置:首页 > 其它

Codeforce385C 树状数组+素因子分解

2015-09-10 22:26 274 查看
题目大意:

给多个区间的询问,在询问区间内每一个出现的素数去计算所有数中有多少个数能被这个素数整除

然后将所有素数得到的对应值求和

这里因为初始给定的数不超过10000000,最多670000不到的素数

而后面给定的区间到达1e9是没意义的,只要后面超过10000000都按最后一个数表示即可

然后将素数的标号作为树状数组的点,保存对应的点前缀和

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <ctime>
#include <cstdlib>
#include <vector>
#include <algorithm>
using namespace std;
#define ll long long
#define N 10001000
#define M 670000
#define pii pair<int,int>
#define lowbit(x) x&(-x)
int prime[M+5] , tot ;
bool check[N+5];

void get_prim()
{
for(int i=2 ; i<=N ; i++){
if(!check[i]) prime[tot++] = i;
for(int j=0 ; j<tot ; j++){
if((ll)i*prime[j]>N) break;
check[i*prime[j]] = true;
if(i%prime[j]==0) break;
}
}
}

int Hash1(int x)
{
if(x>10000000) return 664580; //664579是10000000内素数的数目
int l=0 , r=tot-1 , ans=0;
while(l<=r){
int m = (l+r)>>1;
if(prime[m]>=x){ans = m , r=m-1;}
else l=m+1;
}
return ans+1;
}

int Hash2(int x)
{
if(x>10000000) return 664580;
int l=0 , r=tot-1 , ans=0;
while(l<=r){
int m = (l+r)>>1;
if(prime[m]<=x){ans = m , l=m+1;}
else r=m-1;
}
return ans+1;
}

ll sum[M];

void add(int x , int v){for(int i=x ; i<=tot ; i+=lowbit(i)) sum[i] += v;}

ll query(int x)
{
ll ret = 0;
for(int i=x ; i>0 ; i-=lowbit(i)) ret+=sum[i];
return ret;
}

void fenjie(int x)
{
int mx = (int)sqrt(x+0.5);
for(int i=0 ; i<tot ; i++){
if(prime[i]*prime[i]>x) break;
if(x%prime[i]==0){
//  cout<<"in: "<<i<<" "<<prime[i]<<endl;
add(i+1 , 1);
while(x%prime[i]==0) x/=prime[i];
}
}
if(x>1){
int pos = lower_bound(prime , prime+tot , x)-prime;
add(pos+1 , 1);
}
}

int main() {
// freopen("a.in" , "r" , stdin);
// freopen("out.txt" , "w" , stdout);
get_prim();
int n , m , s , t;
while(~scanf("%d" , &n))
{
for(int i=0 ; i<n ; i++){
int x ;
scanf("%d" , &x);
fenjie(x);
}
scanf("%d" , &m);
while(m--){
scanf("%d%d" , &s , &t);
int p1 = Hash1(s) , p2 = Hash2(t);
//  cout<<p1<<" "<<p2<<endl;
printf("%I64d\n" , query(p2)-query(p1-1));
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: