1. 程式人生 > >二分圖 + 離散

二分圖 + 離散

post mat bcd 優化 代碼 highlight 5.5 put hidden

唐納德是一個數學天才。有一天,他的數學老師決定為難一下他。他跟唐納德說:「現在我們來玩一個遊戲。這個遊戲總共 n 輪,每一輪我都會給你一個數(第 i 輪給出的數是 ai)。你每次要回答一個數,是我給出的這個數的質因數,並且你說出的數不能重復。」

因為數學老師是刻意為難,所以這個遊戲很有可能不可能進行到最後。但是聰明的數學老師早就已經知道這個遊戲最多能進行幾輪了。現在他把問題拋給了你,想看看你知不知道。

註意,1 不是質數。

技術分享圖片

Input

輸入具有如下形式:

na1 a2 an

第一行一個整數 n (1n3 000)。

第二行 n 個整數用空格隔開,a1,a2,,an (2ai106

)。

Output

輸出遊戲最多能進行幾輪。

Examples

Input
3
7 6 3
Output
3
Input
5
2 2 2 2 2
Output
1

思路 : 首先 要找出 每個數所有的不同質因數, 然後 我寫了一個深搜 , 不出所料 , 超時了
    然後 細細想想,由於每個數只能對應一個數,因此可以用二分圖匹配去搞,再由於質因數的範圍比較大,因此可以離散,建邊去匹配 , 但是 , 又超時了 !
    然後我就開始 懷疑二分匹配的復雜度是不是太高了,一頓百度,還沒找到, 又想到了 是不是我找質因數的時候復雜度太高了,我優化了一下找質因數的方法,果然A了
    一個數的質因數只需要找到 根號 n ,因為不可能存在兩個質因數大於 根號 n
代碼示例 :
const int eps = 1e6+5;
#define ll long long

bool pt[1000];
vector<int> pre[3005];
int n;
int xx[10000];
bool ff[eps];
int pp = 1;
bool uu[10000];
int oo[10000];

bool find(int x){
    for(int i = 0; i < pre[x].size(); i++){
        int num = lower_bound(xx+1, xx+pp, pre[x][i]) - xx;
        if (!uu[num]){
            uu[num] = true;
            if (oo[num] == 0 || find(oo[num])){
                oo[num] = x;
                return true;
            }           
        }
    }
    return false;
}

void fun(int k, int x){
    int uu = x;
    for(int i = 2; i <= sqrt(uu)+1; i++){
        if (pt[i]){
            int f = i;
            if (x % f == 0){
                pre[k].push_back(f);
                if (!ff[f]) {
                    xx[pp++] = f; 
                    ff[f] = true;
                }
            }
            while(x % f == 0) x /= f;
        }
        if (x == 1) break;
    }
    if (x != 1){
        pre[k].push_back(x);
        if (!ff[x]){
            xx[pp++] = x;
            ff[x] = true;
        }
    }
}

int main() {
    cin >> n;
    int cn;
    
    memset(pt, true, sizeof(pt));
    for(int i = 2; i <= 1000; i++){
        if (pt[i]) {
            for(int j = i + i; j <= 1000; j += i){
                pt[j] = false;
            }
        }
    }
    memset(ff, false, sizeof(ff)); 
    for(int i = 1; i <= n; i++){
        scanf("%d", &cn);
        fun(i, cn);
        //pre[i].erase(unique(pre[i].begin(), pre[i].end()), pre[i].end());
    }
    sort(xx+1, xx+pp); 
    memset(oo, 0, sizeof(oo));
    //for(int i = 1; i <= n; i++){
        //for(int j = 1; j < pp; j++){
            //if (edge[i][j]) printf("%d ", 1);
            //else printf("0 ");
        //}
        //printf("\n");
    //}
    int ans = 0;
    for(int i = 1; i <= n; i++){
        memset(uu, false, sizeof(uu));
        if (find(i)) {
            ans++;
        }
        else break;
    }
    printf("%d\n", ans);

    return 0;
}


二分圖 + 離散