CJOJ 1504 整数合并

整数合并

Description

现在给你一些连续的整数,它们是从 A 到 B 的整数。一开始每个整数都属于各自的集合,然后你需要进行如下操作:
每次选择两个属于不同集合的整数,如果这两个整数拥有大于等于 P 的公共质因子,那么把他们所在的集合合并。
反复上述操作,直到没有可以合并的集合为止。
现在,小 X 想知道,最后有多少个集合。

Input

一行,三个整数 A,B,P

Output

一个数,表示最终集合的个数。

Sample Input

10 20 3

Sample Output

7

Hint

样例解释:
解释: {10 , 20 , 12 , 15 , 18} , {11},{13} , {14} , {16} , {17} , {19}
【数据规模】
B<=1000. 80%数据
A<=B<=100000; 2<=P<=B

Source

并查集 ,数学 ,数论

Solution

对于有相同质因数的数字加入一个集合,最后统计集合的个数即可(爸爸是自己的点的个数)

Code

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define L 100010
#define LL long long
using namespace std;

int a, b, p, prim[L], cnt, f[L], ans;
bool check[L];

inline int find(int x) { return (f[x] == x) ? x : f[x] = find(f[x]);}
inline void makeset(int x, int fa) {f[find(x)] = f[find(fa)];}

int main() {
  freopen("CJOJ1504.in", "r", stdin);
  freopen("CJOJ1504.out", "w", stdout);
  scanf("%d %d %d", &a, &b, &p);
  for (int i = a; i <= b; ++i) f[i] = i;
  for (int i = 2; i <= b; ++i) {
    if (!check[i]) prim[++cnt] = i;
    for (int j = 1; j <= cnt && i * prim[j] <= b; ++j) {
      check[prim[j] * i] = 1;
      if (i % prim[j] == 0) break;
    }
  }
  for (int i = 1; i <= cnt; ++i)
    if (prim[i] >= p) {
      int c = a / prim[i] * prim[i];
      if (c != a) c += prim[i];
      for (int j = c + prim[i]; j <= b; j += prim[i]) makeset(j, c);
    }
  for (int i = a; i <= b; ++i) if (f[i] == i) ans++;
  printf("%d\n", ans);
  return 0;
}

Summary

注意合并集合的时候试讲他们的父亲放在一起,以及初始化的时候初始自己的父亲是自己

你可能感兴趣的:(数论)