小Y增员操直播群

题目大意

n n 个人,初始一个人一个联通块,编号都是0
每次两个联通块合并,假设较小联通块大小是 x x ,较大联通块编号为y的会与较小联通块大小是 y mod x y   m o d   x 的连边,然后编号变成 y+x y + x ,接下来合并两个联通块。
最终所有人都在一个联通块内。
现在给你最终联通块中所有连边情况,已知一天里联通块合并可以并行,问最少多少天能合并出来。

做法

考虑一个递归过程,任意时刻联通块对应最终联通块一个编号区间。
我们要尝试分割它,满足题目所说的条件。
假设是分割 0 0 n1
n1 n − 1 连的最小编号是 x x ,因为n1一定在较大联通块,所以 x x 一定在较小联通块。
假设较小联通块大小为y,有 (n1) mod y=x ( n − 1 )   m o d   y = x
如果两个联通块不相等,因为后面那个更大,显然可以找到 (nx2) mod y=y1 ( n − x − 2 )   m o d   y = y − 1
那么 nx2 n − x − 2 连向的最小编号就是分界线。
能找分界线本题显然就能解决。

#include<cstdio>
#include<algorithm>
#include<vector>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
#define pb push_back
using namespace std;
const int maxn=100000+10;
vector<int> e[maxn];
int i,j,k,l,t,n,m,tot,ans,ca;
bool czy;
int solve(int l,int r){
    if (l==r&&!e[r].size()) return 0;
    if (l>r||!e[r].size()) return -1;
    int mid=e[r].back();
    if (r-mid>mid-l+1){
        if (!e[r-(mid-l+1)].size()) return -1;
        int tmp=e[r-(mid-l+1)].back();
        if (tmp<mid) return -1;
        mid=tmp;
    }
    if (r-mid<mid-l+1||mid<l) return -1;
    int now=(r-mid-1)%(mid-l+1);
    int i;
    fd(i,r,mid+1){
        if (!e[i].size()) return -1;
        if (e[i].back()-l!=now) return -1;
        e[i].erase(e[i].end()-1);
        if (now==0) now=mid-l;else now--;
    }
    int j=solve(l,mid),k=solve(mid+1,r);
    if (j<0||k<0) return -1;
    else return max(j,k)+1;
}
int main(){
    freopen("gymnastics.in","r",stdin);freopen("gymnastics.out","w",stdout);
    scanf("%d",&ca);
    while (ca--){
        scanf("%d%d",&n,&m);
        fo(i,0,n-1) e[i].clear();
        fo(i,1,m){
            scanf("%d%d",&j,&k);
            if (j<k) swap(j,k);
            e[j].pb(k);
        }
        fo(i,0,n-1){
            sort(e[i].begin(),e[i].end());
            reverse(e[i].begin(),e[i].end());
        }
        ans=solve(0,n-1);
        printf("%d\n",ans);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值