原来求质数对还可以这样求

背景:最近想玩玩数论,偶然去51nod找了一题和质数相关的题目,最讨厌做质数相关的题了QAQ。题目链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1439

题意:

给定n个数,q个操作

下面n个数 a1-an


开始有一个空的集合

每个操作一个数字 u (1<=u<=n) 表示把 a[u] 插入集合(若集合中没有a[u]), 否则就把a[u]从集合中删除

每个操作结束后输出 当前集合内有多少对数 是互质的。

这道题关键解决一个问题就是:已知有一些数的集合S,给出一个下标index,问arr[index]能与S集合中的数字组成多少对质数对(PS:C集合可能存在多个数值相同的数,但由于下标不同,故算作不同的数)

做法:分解质因子,dfs爆搜做容斥。

变量解析:

c[]:存因子,除去1。

f[]:存因子出现的次数

vector<int> G[]:G[i]为值为i的质因子的结合。

set<int> s;

#include <iostream>  
#include <fstream>  
#include <string>  
#include <time.h>  
#include <vector>  
#include <map>  
#include <queue>  
#include <algorithm>  
#include <cstring>  
#include <cmath>  
#include <set>  
#include <vector>

using namespace std;
typedef long long ll;
const int maxn = 5e5+10;
int prime[maxn],primenum;
int n,q;
int arr[maxn]; 
vector<int> G[maxn];
ll ans;
set<int> s;
int top,one;
int f[maxn];
int c[maxn];

template<class T>
inline bool rd(T &ret){
	char c;
	int sgn;
	if(c = getchar(),c == EOF) return 0;
	while(c != '-' &&(c < '0' ||c > '9')) c = getchar();
	sgn = (c == '-')?-1:1;
	ret = (c == '-')?0:(c-'0');
	while(c = getchar(),c>='0'&&c<='9') ret = ret * 10 + (c-'0');
	ret *= sgn;
	return 1;
}

template<class T>
inline void pt(T x){
	if(x<0){
		putchar('-');
		x = -x;
	}
	if(x>9) pt(x/10);
	putchar(x%10+'0');
}


void PRIME(ll max_prime){
	primenum = 0;
	prime[primenum++] = 2;
	for(ll i = 3; i <= max_prime; i += 2){
		for(ll j = 0; j < primenum; j++){
			if(i%prime[j] == 0) break;
			else if(prime[j]>sqrt((double)i)||j == primenum - 1){
				prime[primenum++] = i;
				break;
			}
		}
	}
}

void pre(int index,int val){
	for(int i = 0; prime[i] * prime[i] <= val;i++){
		if(val%prime[i] == 0){
			while(val%prime[i] ==0)
				val /= prime[i];
			G[index].push_back(prime[i]);
		}
	}
	if(val != 1) G[index].push_back(val);
}

void dfs(int t,int index,int cnt,int flag,int val){//flag标记1插入,-1删除 
	printf("val: %d\n",val); 
	if(t >= (int)G[index].size()){
		if(cnt == 0) return;
		ans += f[val] * flag;
		c[top++] = val;
		return;
	}
	dfs(t+1, index , cnt , flag , val);
	dfs(t+1, index , cnt+1 , flag*(-1), val*G[index][t]);
}

int main(){
	PRIME(maxn);
	rd(n);rd(q);
	for(int i = 1; i <= n; i++){
		rd(arr[i]);
		pre(i,arr[i]);//预处理出下标为i,值为arr[i]的质因子 
	}
	
	for(int i = 1;i <= n; i++){
		for(int j = 0; j < G[i].size(); j++){
			printf("%d ",G[i][j]);
		}
		printf("\n");
	} 
	
	
	ans = 0,one = 0;
	int index;
	while(q--){
		rd(index);
		if(arr[index] == 1){//index下标对应的值是1 
			if(s.count(index)){
				s.erase(index);
				ans -= s.size();
			}
			else{
				ans += s.size();
				s.insert(index);
			}
			
		}else{
			if(s.count(index)){//存了index这个下标 
				s.erase(index);
				ans -= s.size();//先当成都是互质的

				top = 0;
				dfs(0,index,0,-1,1);
				ans--;
				for(int i = 0; i < top; i++){
					f[c[i]]--;
				}
				
			}else{
				ans +=  s.size();
				s.insert(index);
				
				top = 0;
				dfs(0,index,0,1,1);
				for(int i = 0; i < top; i++){
					f[c[i]]++;//f[i]表示质数为i的个数 
				}
				
			}
		}
		pt(ans);
		puts("");
	}
	return 0;
}

例如集合中已经存在了1、2、3、4、6,那么f[2] = 3,f[3] = 2,f[6] = 1,此时集合中质数对有6对。当往S中插入30,假设集合中所有数与30都组成质数对,6+5=11;接下来bfs容斥,结果为11--f[2]-f[3]-f[5]+f[6]+f[10]+f[15]-f[30] = 11 - 3 -2 -0 +1 +0 +0 +0 = 7;然后f[2],f[3],f[5],f[6],f[10,f[15],f[30]都加1。




  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值