洛谷P1621-集合
阿新 • • 發佈:2018-08-19
rod 一行 des script esp bound 規模 如果 ron
Problem 洛谷P1621-集合
Accept:496 Submit: 1.4k
Time Limit: 1000 mSec Memory Limit : 128MB
Problem Description
現在給你一些連續的整數,它們是從A到B的整數。一開始每個整數都屬於各自的集合,然後你需要進行一下的操作:
每次選擇兩個屬於不同集合的整數,如果這兩個整數擁有大於等於P的公共質因數,那麽把它們所在的集合合並。
反復如上操作,直到沒有可以合並的集合為止。
現在Caima想知道,最後有多少個集合。
Input
一行,三個整數A,B,P。
【數據規模】
A≤B≤100000;
2≤P≤B。
Output
一個數,表示最終集合的個數。
Sample Input
10 20 3
Sample output
7
題目鏈接:https://www.luogu.org/problemnew/show/P1621
題解:水題,之所以記錄一下是因為感覺自己在做這道題的時候才感覺真的弄明白了歐拉篩的證明,以前會證明,但是感覺是只是機械化的證明,沒有自己的理解。
我認為證明中最精華的一句話是,在i%prime[j] == 0,之前,prime[j]均為i*prime[j]的最小素因子,這個結論很顯然,但是起到了決定性作用......
篩完素數就是簡單的並查集。
1 #include <iostream> 2#include <cstdio> 3 #include <cstring> 4 #include <cstdlib> 5 #include <algorithm> 6 using namespace std; 7 8 const int maxn = 100000+10; 9 bool is_prime[maxn]; 10 int tot,prime[maxn]; 11 int pre[maxn]; 12 int a,b,p; 13 14 void get_Prime(){ 15 memset(is_prime,true,sizeof(is_prime)); 16 is_prime[0] = is_prime[1] = false; 17 tot = 0; 18 for(int i = 2;i < maxn-1;i++){ 19 if(is_prime[i]) prime[tot++] = i; 20 for(int j = 0;j<tot && prime[j]<=maxn/i;j++){ 21 is_prime[i*prime[j]] = false; 22 if(i%prime[j] == 0) break; 23 } 24 } 25 } 26 27 int findn(int x){ 28 return x == pre[x] ? x : pre[x] = findn(pre[x]); 29 } 30 31 void merge_node(int x,int y){ 32 int fx = findn(x),fy = findn(y); 33 if(fx != fy){ 34 pre[fx] = fy; 35 } 36 } 37 38 int main() 39 { 40 //freopen("input.txt","r",stdin); 41 get_Prime(); 42 scanf("%d%d%d",&a,&b,&p); 43 for(int i = a;i <= b;i++){ 44 pre[i] = i; 45 } 46 int pos = lower_bound(prime,prime+tot,p)-prime; 47 for(int i = pos;prime[i] <= b;i++){ 48 for(int j = 2;j*prime[i] <= b;j++){ 49 if((j-1)*prime[i] < a) continue; 50 merge_node((j-1)*prime[i],j*prime[i]); 51 } 52 } 53 int cnt = 0; 54 for(int i = a;i <= b;i++){ 55 if(pre[i] == i) cnt++; 56 } 57 printf("%d\n",cnt); 58 return 0; 59 }
洛谷P1621-集合