分解一个在 N范围内 的数 的 质因数
我们首先想到的是把 N 范围内 的所有素数O(N)的筛选出来,然后while跑质数表,来达到加速查找的目的。
但是现在 我们可以发现 , 一个数X , 它的质因数 肯定在 sqrt(X)内是 最多的
令 Y = sqrt(X) , 假设 Y现在是一个质数 , 那么 后面明显就不会有 X的质因数 , 所以 我们进行分解质因数的时候,可以只筛到sqrt(X)就可以了 , 假设我们现在要对 Q 个(1 <= Q <= 1e5) 数字进行筛选 , 每个数字 Ai 的大小是 (1 <= Ai <= 1e6)
那么可以在1e8 的复杂度内完成 。
bool valid[Maxn];
int prime[Maxn] , ast;
vector <int> G[Maxn>>2];
void getPrime(int n , int &ast){
memset(valid , true , sizeof(valid));
for(int i = 2 ; i <= n ; i++){
if(valid[i]){
ast++;
prime[ast]=i;
}
for(int j = 1 ; (j<=ast) && (i*prime[j] <= n) ; j++){
valid[i*prime[j]] = false;
if(i % prime[j] == 0) break;
}
}
}
int main()
{
ast = 0;
getPrime(1007 , ast);
scanf(" %d %d",&N,&M);
for(int i = 1 ; i <= N ; i++){
int x; scanf(" %d",&x);
for(int j = 1 ; j <= ast ; j++){
while(x % prime[j] == 0){
G[i].push_back(prime[j]);
x /= prime[j];
}
}
if(x != 1) G[i].push_back(x);
}
}
超过了 sqrt(X) 部分的质因数 , 我们可以通过 X != 1 来判断 , 说明现在剩下的X必定是一个质因数 , 直接塞进vector即可
“美登杯”上海市高校大学生程序设计邀请赛 (华东理工大学)
这场比赛的 E题 就利用了这个性质,完美维护质因数。
代码:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <iostream>
#include <cmath>
#include <map>
#include <queue>
#include <algorithm>
#include <set>
#include <vector>
#include <stack>
#define Clear( x , y ) memset( x , y , sizeof(x) );
#define Qcin() std::ios::sync_with_stdio(false);
using namespace std;
typedef long long LL;
const int Maxn = 1e6 + 7;
const int Inf = 1e9 + 7;
const LL Mod = 1e9 + 7;
int N , M;
bool valid[Maxn];
int prime[Maxn] , ast;
vector <int> G[Maxn>>2];
void getPrime(int n , int &ast){
memset(valid , true , sizeof(valid));
for(int i = 2 ; i <= n ; i++){
if(valid[i]){
ast++;
prime[ast]=i;
}
for(int j = 1 ; (j<=ast) && (i*prime[j] <= n) ; j++){
valid[i*prime[j]] = false;
if(i % prime[j] == 0) break;
}
}
}
int Add , Sub;
struct edge{
int l , r;
int add , sub;
}tree[Maxn];
void Build(int l , int r , int x){
tree[x].l = l , tree[x].r = r;
tree[x].add = tree[x].sub = 0;
if( l == r ) return;
int mid = ( l + r ) / 2;
Build( l , mid , x * 2 );
Build( mid + 1 , r , x * 2 + 1 );
}
void PushDown( int x ){
if(tree[x].add || tree[x].sub){
if(tree[x<<1].add >= tree[x].sub) tree[x<<1].add -= tree[x].sub;
else tree[x<<1].sub += (tree[x].sub - tree[x<<1].add) , tree[x<<1].add = 0;
if(tree[x<<1|1].add >= tree[x].sub) tree[x<<1|1].add -= tree[x].sub;
else tree[x<<1|1].sub += (tree[x].sub - tree[x<<1|1].add) , tree[x<<1|1].add = 0;
tree[x<<1].add += tree[x].add;
tree[x<<1|1].add += tree[x].add;
tree[x].sub = tree[x].add = 0;
}
}
void Update_line( int L , int R , int add , int x ){
if( L <= tree[x].l && tree[x].r <= R ){
if(add == 1){
tree[x].add++;
} else {
if(tree[x].add) tree[x].add--;
else tree[x].sub++;
}
return;
}
PushDown(x);
int mid = ( tree[x].l + tree[x].r ) / 2;
if( L <= mid ) Update_line( L , R , add , x * 2 );
if( R > mid ) Update_line( L , R , add , x * 2 + 1 );
}
void Query(int L , int R , int x){
if(L <= tree[x].l && tree[x].l == tree[x].r){
Add = tree[x].add , Sub = tree[x].sub;
return;
}
PushDown(x);
int mid = ( tree[x].l + tree[x].r ) / 2;
if(L <= mid) Query(L , R , x * 2);
if(R > mid) Query(L , R , x * 2 + 1);
return;
}
LL Qpow(LL x , LL y){
LL res = 1;
while(y){
if(y & 1) res = res * x % Mod;
x = x * x % Mod;
y = y >> 1;
}
return res % Mod;
}
int main()
{
ast = 0;
getPrime(1007 , ast);
scanf(" %d %d",&N,&M);
for(int i = 1 ; i <= N ; i++){
int x; scanf(" %d",&x);
for(int j = 1 ; j <= ast ; j++){
while(x % prime[j] == 0){
G[i].push_back(prime[j]);
x /= prime[j];
}
}
if(x != 1) G[i].push_back(x);
}
Build(1 , N , 1);
while(M--){
int op; scanf(" %d",&op);
int L , R;
if(op == 1){
scanf(" %d %d",&L,&R);
Update_line(L , R , 1 , 1);
} else if(op == 2){
scanf(" %d %d",&L,&R);
Update_line(L , R , -1 , 1);
} else {
int u;
scanf(" %d",&u);
Query(u , u , 1);
if(Sub >= G[u].size()) printf("1\n");
else {
LL ans = 1;
for(int i = Sub ; i < G[u].size() ; i++){
ans *= (LL)G[u][i];
}
ans = (LL)ans * Qpow((LL)G[u][Sub] , (LL)Add) % Mod;
printf("%lld\n",ans % Mod);
}
}
}
return 0;
}