E题:不是,哥们
思路:
将a[i]*a[i]=k*a[j]转化成a[i]=sqrt(k*a[j]),由于a[i]是整数所以k*a[j]需要是一个完全
平方数,由于a[j]是已知量,所以我们先从a[j]入手。
容易证明a[j]一定可以化为x*y,其中x是一个完全平方数,y是一个非完全平方数。
又因为k*a[j]是一个完全平方数,所以x*y*k是一个完全平方数,可以推出y*k是一个平方数。
又因为y是非完全平方数,所以k一定是y的倍数,设k等于p*y,原式子变成x*y*y*p,
且p也是一个完全平方数。
然后可以先预处理出每个a[j]的最大完全平方数因子,对于每个a[j]求出最小的k=y,然后
遍历k所有的合法取值,即y*p(p是从1开始的完全平方数),答案加上j前面的所有y*p的值。
求最大的完全平方数因子也可以用质因数分解,若幂为偶数即乘上该质因数。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int inf=0x3f3f3f3f;
const int N=1e6+10;
const int mod=1e9+7;
#define fi first
#define se second
#define int long long
int n,a[N];
int cnt[N];
set<int> v[N];
void solve(){
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i];
for(int i=1;i<=n;i++){
for(int j=1;j<=sqrt(a[i]);j++){
if(a[i]%j==0){
if((int)sqrt(j)*(int)sqrt(j)==j)
v[i].insert(j);
int k=a[i]/j;
if((int)sqrt(k)*(int)sqrt(k)==k)
v[i].insert(k);
}
}
}
ll ans=0,maxx=0;
for(int i=1;i<=n;i++){
maxx=max(maxx,a[i]);
int k=a[i]/(*(v[i].rbegin()));
for(int b=1;sqrt(b*b*k*a[i])<=maxx;b++){
int h=sqrt(b*b*k*a[i]);
ans+=cnt[h];
}
cnt[a[i]]++;
}
cout<<ans;
}
signed main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int t=1;
//cin>>t;
while(t--){
solve();
}
return 0;
}
F题:森林的奥秘
思路:
一般这种按输入顺序删点删边的题目,正面都不好想,所以考虑反向思考,
从后往前添加边,考虑直径的变化。
1
没加这条边时森林的直径。
2
A
所在的树的直径。
3
B
所在的树的直。
4
A
和
B
所相连后形成的树的直径。
设f(i)为第i次查询的答案,开两个数组来标记每个树集合的直径所对应的端点
l
和
r
f(i)即是上诉四种情况取
max。
对于第四种情况,一定是左树两直径
u,v,和右树两直径
x,y的其中两点,直接
暴力两两取对求最大值即可。
对于每两点之间的距离,由于是树所以没有环,也就是说每两点只要处于同一连通
块,它们的距离就是建完树后两点间的距离,所以可以先建个图最后跑
lca的倍增算法
求距离。
代码:
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
vector<int> e[N];
int fa[N][21];
int n, m;
int depth[N];
int x[N], y[N];
int l[N], r[N], p[N];
int ans[N];
void BFS(int u) {
queue<int> q;
q.push(u);
memset(depth, 0x3f, sizeof(depth));
depth[u] = 1, depth[0] = 0;
while (q.size()) {
auto t = q.front();
q.pop();
for (auto j : e[t]) {
if (depth[j] > depth[t] + 1) {
depth[j] = depth[t] + 1;
fa[j][0] = t;
q.push(j);
for (int i = 1; i <= 20; i++) {
fa[j][i] = fa[fa[j][i - 1]][i - 1];
}
}
}
}
}
int LCA(int a, int b) {
if (depth[a] < depth[b]) swap(a, b);
for (int i = 20; i >= 0; i--) {
if (depth[fa[a][i]] >= depth[b]) {
a = fa[a][i];
}
}
if (a == b) return a;
for (int i = 20; i >= 0; i--) {
if (fa[a][i] != fa[b][i]) {
a = fa[a][i];
b = fa[b][i];
}
}
return fa[a][0];
}
int getDis(int a, int b) { return depth[a] + depth[b] - 2 * depth[LCA(a, b)]; }
int find(int x) {
if (p[x] != x) p[x] = find(p[x]);
return p[x];
}
void init() {
for (int i = 1; i < N; i++) {
p[i] = i, l[i] = i, r[i] = i;
}
}
int main() {
init();
cin >> n;
for (int i = 1; i < n; i++) {
cin >> x[i] >> y[i];
e[x[i]].push_back(y[i]);
e[y[i]].push_back(x[i]);
}
BFS(1);
ans[n] = 0;
for (int i = n - 1; i >= 1; i--) {
int u = find(x[i]), v = find(y[i]);
int L = 0, R = 0;
p[u] = v;
int maxx = -1;
int dis = 0;
dis = getDis(l[u], l[v]);
if (dis > maxx) {
maxx = dis;
L = l[u], R = l[v];
}
dis = getDis(l[u], r[v]);
if (dis > maxx) {
maxx = dis;
L = l[u], R = r[v];
}
dis = getDis(r[u], l[v]);
if (dis > maxx) {
maxx = dis;
L = r[u], R = l[v];
}
dis = getDis(r[u], r[v]);
if (dis > maxx) {
maxx = dis;
L = r[u], R = r[v];
}
dis = getDis(l[u], r[u]);
if (dis > maxx) {
maxx = dis;
L = l[u], R = r[u];
}
dis = getDis(l[v], r[v]);
if (dis > maxx) {
maxx = dis;
L = l[v], R = r[v];
}
l[v] = L, r[v] = R;
ans[i] = max(ans[i + 1], maxx);
}
for (int i = 1; i <= n; i++) {
cout << ans[i] << endl;
}
return 0;
}