数列+车辆销售

42 篇文章 0 订阅
13 篇文章 0 订阅

这里写图片描述
这就是更相减损之术。
直接模拟太慢。
搞成辗转相除。
对于a,b不一样的数的个数为a/b
然后按求GCD的方法递归下去

#include <cstdio>
#include <iostream>
#include <cstring>
#define ll long long
using namespace std;    
ll ans=0;
ll abs(ll x)
{
    if(x<0) x=-x;
    return x;
}
int main()
{
    freopen("seq.in","r",stdin);
    freopen("seq.out","w",stdout);
    ll a,b;

    scanf("%lld%lld",&a,&b);
    /*vis[a]=vis[b]=1;
    ans=2;
    if(a<b) swap(a,b);
    for(int i=1;i<=100;i++)
     {
        //printf("%lld ",abs(a-b));
        ll tmp=abs(a-b);
        if(!vis[tmp]) vis[tmp]++,ans++; 
        a=b;
        b=tmp;
     }*/
    if(a<b) swap(a,b);
    ans=1;
    while(b)
    {
        //printf("%lld %lld %lld\n",a,b,a/b);
        ans+=a/b;
        ll tmp=b;
        b=a%b;
        a=tmp;
    }
    printf("%lld",ans);

    return 0;
}

这里写图片描述
暴力写挂了。。。。。本来以为能得点分呢。


正解:
明白一个问题。
真正的需要的边一定是在最大生成树中。
为啥?
一个车在最大生成树中都跑不过去。那么在所有边构成的图中,也是不能跑过去的。


用克鲁斯卡尔求最大生成树,在并查集合并时,把原本的一个根连向另一
个根改成两个根都连向一个新建的节点,并把当前正在处理的边的权值赋给这
个新节点做点权。这样形成的结构会是一棵树。
一个点的答案大致上是树的根到自己的路径上,相邻两个节点的子树叶节
点数的平方和。需要注意的是父子两个节点权值相同的情况,这个部分需要特
殊处理。


我的理解:这个点的权值可以理解为车的重量。
一个车的重量不为任何一个道路的容量是毫无贡献的。


顺便吐槽一下,MMP,题目的数据范围是错的?!
WTF

#include <cstdio>
#include <iostream>
#include <algorithm>
#define ll long long
using namespace std;
const int maxm=610000;
struct node{
    int x,y,cap;
}a[2*maxm];
int son[maxm][2];
int fat[2*maxm],val[maxm];
ll ans[maxm],size[2*maxm];
int num;
bool comp(node xx,node yy)
{
    return xx.cap>yy.cap;
}
int find(int x)
{
    if(fat[x]==x) return x;
    return fat[x]=find(fat[x]);
}
void dfs(int x,int fa,ll sum)
{
    ll net=0;
    if(fa)
    {
        if(val[fa]==val[x]) size[x]=size[fa];//搞到不一样的地方再统计 
        else net=(size[fa]-size[x])*(size[fa]-size[x]);
    }
    if(son[x][0])//最后的图上实点是木有儿子的 
    {
        dfs(son[x][0],x,sum+net);
        dfs(son[x][1],x,sum+net);
    }
    else ans[x]=sum+net;
}
int main()
{
    freopen("car.in","r",stdin);
    freopen("car.out","w",stdout);
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
     scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].cap);
    sort(a+1,a+m+1,comp);
    for(int i=1;i<=n;i++) fat[i]=i,size[i]=1;
    num=n;
    int tot=n;
    for(int i=1;i<=m;i++)
    if(find(a[i].x)!=find(a[i].y))
    {
        tot--;
        num++;
        int xx=find(a[i].x),yy=find(a[i].y);
        fat[find(a[i].x)]=fat[find(a[i].y)]=num;
        fat[num]=num;
        son[num][0]=xx,son[num][1]=yy;
        val[num]=a[i].cap;
        size[num]=size[xx]+size[yy];
        //printf("%d %d %d\n",xx,yy,num);
        //if(tot==1) break;
    }
    dfs(num,0,0);
    for(int i=1;i<=n;i++)
     printf("%lld ",ans[i]); 
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值