傳送門
文章目錄
題意:
給你nnn個數,每個數的因子個數不超過777個,選出最少的數使其乘積為平方數。
n≤1e5n\le 1e5n≤1e5
思路:
由于因子不超過777個,所以由約數個數(1+p1)?(1+p2)?...?(1+pn)(1+p_1)*(1+p_2)*...*(1+p_n)(1+p1?)?(1+p2?)?...?(1+pn?)得其質因子個數不超過222個,啟發我們用質因子來做這個題。
一個顯然的性質就是平方數的質因子冪次mod2\bmod 2mod2之后這個平方數為111。所以我們將每個數的質因子冪次mod2\bmod 2mod2之后留下為冪次111的質因子。現在問題就變成了選出盡可能少的點使其乘積的質因子冪次為偶數,考慮將其轉換成圖上的問題。
如果一個數本身就是平方數那么直接輸出111就好啦,下面討論質因子個數不為000的情況。
先考慮每個數的質因子都有兩個的情況,考慮以質數為每個點,將每個數的兩個質因子連邊,那么畫出來圖之后可以發現最小環即為答案。
如果質因子只有一個怎么辦呢?考慮建立一個虛擬節點111,將其與111連邊,之后跑最小環就好啦。
那么問題來了,最小環?FloydFloydFloyd?顯然是不可以的,我們需要發現我們構建的圖的一些特殊性質。
首先邊權都為111且為無向圖,那么我們可以枚舉起點,遍歷每條邊,記一個depthdepthdepth,每當碰到的depthdepthdepth被更新過了,那么ans=min(ans,depth[u]+depth[v]+1)ans=min(ans,depth[u]+depth[v]+1)ans=min(ans,depth[u]+depth[v]+1)即可,但是復雜度是n2n^2n2的仍然不可接受。
繼續考慮優化起點,由于>1000>1000>1000的質數不會相互連邊,所以只需枚舉≤1000\le1000≤1000的質數即可,復雜度nan\sqrt ana?,可以接受。
#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<map>
#include<cmath>
#include<cctype>
#include<vector>
#include<set>
#include<queue>
#include<algorithm>
#include<sstream>
#include<ctime>
#include<cstdlib>
#define X first
#define Y second
#define L (u<<1)
#define R (u<<1|1)
#define pb push_back
#define mk make_pair
#define Mid (tr[u].l+tr[u].r>>1)
#define Len(u) (tr[u].r-tr[u].l+1)
#define random(a,b) ((a)+rand()%((b)-(a)+1))
#define db puts("---")
using namespace std
;
typedef long long LL
;
typedef unsigned long long ULL
;
typedef pair
<int,int> PII
;const int N
=1000010,mod
=1e9+7,INF
=0x3f3f3f3f;
const double eps
=1e-6;int n
;
int a
[N
];
int e
[N
],ne
[N
],h
[N
],idx
;
int prime
[N
],cnt
,ans
=INF
;
int depth
[N
];
bool st
[N
];
vector
<int>v
;void add(int a
,int b
) {e
[idx
]=b
,ne
[idx
]=h
[a
],h
[a
]=idx
++;
}void divide(int x
) {int a
,b
; a
=b
=-1;for(int i
=2;i
<=x
/i
;i
++) {if(x
%i
==0) {int cnt
=0;while(x
%i
==0) x
/=i
,cnt
++;if(cnt
%2==0) continue;if(a
==-1) a
=i
;else if(b
==-1) b
=i
;}}if(x
>1) {if(a
==-1) a
=x
;else b
=x
;}if(a
==-1) {puts("1");exit(0);}if(b
==-1) add(1,a
),add(a
,1);else add(a
,b
),add(b
,a
);
}void get_prime(int n
) {for(int i
=2;i
<=n
;i
++) if(!st
[i
]) {for(int j
=i
+i
;j
<=n
;j
+=i
) st
[j
]=1;prime
[++cnt
]=i
;}
}void bfs(int st
) {queue
<int>q1
,q2
;memset(depth
,-1,sizeof(depth
));q1
.push(st
); q2
.push(-1);depth
[st
]=0;while(q1
.size()) {int a
=q1
.front(); q1
.pop();int b
=q2
.front(); q2
.pop();for(int i
=h
[a
];~i
;i
=ne
[i
]) {int j
=e
[i
];if((i
^1)==b
) continue;if(depth
[j
]==-1) depth
[j
]=depth
[a
]+1,q1
.push(j
),q2
.push(i
);else ans
=min(ans
,depth
[a
]+depth
[j
]+1);}}
}int main()
{
get_prime(2000);memset(h
,-1,sizeof(h
));scanf("%d",&n
);for(int i
=1;i
<=n
;i
++) {scanf("%d",&a
[i
]);divide(a
[i
]);}for(int i
=1;i
<=cnt
;i
++) bfs(i
);printf("%d\n",ans
==INF
? -1:ans
);return 0;
}
總結
以上是生活随笔為你收集整理的Codeforces Round #628 (Div. 2) E. Ehab‘s REAL Number Theory Problem 巧妙的质因子建图的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。