唐纳德是一个数学天才。有一天,他的数学老师决定为难一下他。他跟唐纳德说:「现在我们来玩一个游戏。这个游戏总共 n 轮,每一轮我都会给你一个数(第 i 轮给出的数是 ai)。你每次要回答一个数,是我给出的这个数的质因数,并且你说出的数不能重复。」
因为数学老师是刻意为难,所以这个游戏很有可能不可能进行到最后。但是聪明的数学老师早就已经知道这个游戏最多能进行几轮了。现在他把问题抛给了你,想看看你知不知道。
注意,1 不是质数。
Input
输入具有如下形式:
na1 a2 … an
第一行一个整数 n (1≤n≤3 000)。
第二行 n 个整数用空格隔开,a1,a2,…,an (2≤ai≤106)。
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; }