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

来源:互联网 发布:如何面试java架构师 编辑:程序博客网 时间:2024/05/15 00:23

背景:最近想玩玩数论,偶然去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。




原创粉丝点击