山东理工大学第十六届ACM程序设计竞赛

题目链接

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;
}

  • 11
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值