刷题#R8

100 篇文章 0 订阅
26 篇文章 0 订阅

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

T1
这是一个更相减损。
出现的所有的不同的数就是更相减损过程中出现的;
直接这样做的话,会T或者爆;
再进一步分析一下,就会发现,我们可以把更相减损优化为辗转相除,因为多几次更相减损就是辗转相除,那么不同数的个数在辗转相除中就是每次的a/b,因为a只有减损a/b次才会达到b,a%b的状态,这之间的数是递减的,不会出现重复。

T2
50分,我们可以倒着加边,添加进新的边时,用并查集维护,合并集合时,把每个集合新加进的点的个数记下来,这一轮结束后,ans[i]+=ad[i]*ad[i]就可以了。
100分:
用克鲁斯卡尔算法求最大生成树,在并查集合并时,把原本的一个根连向另一
个根改成两个根都连向一个新建的节点,并把当前正在处理的边的权值赋给这
个新节点做点权。这样形成的结构会是一棵树。
一个点的答案大致上是树的根到自己的路径上,相邻两个节点的子树叶节
点数的平方和。需要注意的是父子两个节点权值相同的情况,这个部分需要特
殊处理。(看代码会比较容易理解)

T3
不是太会。

T1

#include<iostream> 
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long
using namespace std;
LL a1,a2,ans;
LL gcd(LL a,LL b)
{
    if(!b) return a;
    ans+=a/b;
    return gcd(b,a%b);
}
int main()
{
    freopen("seq.in","r",stdin);
    freopen("seq.out","w",stdout);
    scanf("%lld%lld",&a1,&a2);
    if(a1<a2) swap(a1,a2);
    gcd(a1,a2);
    ans++;//0也算一种 
    printf("%lld\n",ans);
    return 0;
}

T2
50分

#include<iostream> 
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<ctime>
#define LL long long
using namespace std;
const int N=100009;
const int M=200009;
const int inf=(1e9);
int n,m;
struct H{
    int x,y,z;
}e[M];
int a[M],cnt,f[N];
LL ans[N],siz[N],ad[N]; 
bool cmp(H w1,H w2)
{
    return w1.z>w2.z;
}
int find(int x)
{
    return f[x]==x?x:f[x]=find(f[x]);
}
void add(int o)
{
    int fx=find(e[o].x);
    int fy=find(e[o].y);
    if(fx!=fy)
    {
        for(int i=1;i<=n;i++)
        {
            int ff=find(i);
            if(ff==fx)
              ad[i]+=siz[fy];
            else
            if(ff==fy)
              ad[i]+=siz[fx];
        }
        f[fx]=fy;
        siz[fy]+=siz[fx];
    }
}
int main()
{
    freopen("car.in","r",stdin);
    freopen("car.out","w",stdout);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
        scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].z);
    sort(e+1,e+m+1,cmp);
    for(int i=1;i<=m;i++) if(e[i].z!=a[cnt]) a[++cnt]=e[i].z; 
    for(int i=1;i<=n;i++) f[i]=i,siz[i]=1;

    int t=1;
    for(int i=1;i<=cnt;i++)
    {
        int flag=0;
        while(e[t].z>=a[i]&&t<=m)
        {
            add(t);
            t++;
            flag=1;
        }
        if(f)
        for(int i=1;i<=n;i++)
        {
            ans[i]+=ad[i]*ad[i];
            ad[i]=0;
        }
        if(t>m) break;
    }   
    for(int i=1;i<=n;i++)
      printf("%lld ",ans[i]);
    return 0;
}

100分(打了一遍找不到了,贴标程吧qaq)

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int N = 510000;
typedef long long ll;
struct node
{
    int u, v, l;
    bool operator < (const node &no) const
    {
        return l > no.l;
    }
}e[N];

int n, m, newn;
int son[N][2];
int fa[N], size[N], value[N];
ll ans[N];


int read()
{
    char ch = getchar();
    int x = 0;
    while (!isdigit(ch)) ch = getchar();
    while (isdigit(ch)) {x = x*10+(ch-'0');ch=getchar();}
    return x;
}

int getf(int x)
{
    if (fa[x] == x) return x;
    fa[x] = getf(fa[x]);
    return fa[x];
}

void dfs(int u, int fa, ll cnt)
{
    ll delta = 0;
    if (fa)
    {
        if (value[u] == value[fa]) size[u] = size[fa];
        else delta = (ll)(size[fa] - size[u]) * (ll)(size[fa] - size[u]);
    }
    if (son[u][0])
    {
        dfs(son[u][0], u, cnt + delta);
        dfs(son[u][1], u, cnt + delta);
    }
    else ans[u] = cnt + delta;
}


int main()
{   
    freopen("car.in","r",stdin);
    freopen("car.out","w",stdout);
    n = read(), m = read();
    for (int i = 1; i <= m; i++)
    {
        e[i].u = read();
        e[i].v = read();
        e[i].l = read();
    }
    sort(e + 1, e + 1 + m);
    for (int i = 1; i <= n; i++) fa[i] = i;

    newn = n;
    for (int i = 1; i <= n; i++) size[i] = 1;


    for (int i = 1; i <= m; i++)
    {
        int u = getf(e[i].u), v = getf(e[i].v);
        if (u == v) continue;
        newn++;
        son[newn][0] = u;
        son[newn][1] = v;
        fa[u] = fa[v] = newn;
        fa[newn] = newn;
        value[newn] = e[i].l;
        size[newn] = size[u] + size[v];
    }
    dfs(newn, 0, 0);
    for (int i = 1; i <= n; i++)
        printf("%lld ", ans[i]);
    printf("\n");
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值