刷题#R8

来源:互联网 发布:思科show mac 编辑:程序博客网 时间:2024/04/28 08:47

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

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 longusing 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 longusing 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;}
原创粉丝点击