2024牛客暑期多校训练营 第四场

G Horse Drinks Water

G-Horse Drinks Water_2024牛客暑期多校训练营4 (nowcoder.com)

这题就是初中学过的将军饮马问题,只需要走一遍x轴的 和一遍y轴 , 取小就可以了

void solve(){
        int x1, y1, x2, y2;
        cin >> x1 >> y1 >> x2 >> y2;
        double ret1 = (x2 - x1) * (x2 - x1) + (y2 + y1) * (y2 + y1);
        ret1 = sqrt(ret1);
        double ret2= (x2 + x1) * (x2 + x1) + (y2 - y1) * (y2 - y1);
        ret2 = sqrt(ret2);
        ret1 = min(ret1, ret2);
        printf("%.10lf\n", ret1);
}

I Friends

I-Friends_2024牛客暑期多校训练营4 (nowcoder.com)

对于这种类似的区间问题 , 不难想到,比如当我们有区间 [l,r],那么区间内的每对人都是好朋友,所以我们可以暴力的去对于每个人枚举他右边的连续区间 , 然后取一个交集即可

int n ,m ,r[N];
vector<int>g[N];
void solve(){
  cin>>n>>m;
  for(int i =1;i<=m;++i){
    int u ,v;
    cin>>u>>v;
    g[u].push_back(v);
    g[v].push_back(u);
  }

  for(int i =1;i<=n;++i)sort(all(g[i]));
  for(int i =1;i<=n;++i){
    int now = i;
    r[i] = i;
    for(auto to : g[i]){
      if(to < now)continue;
      if(to == now+1){
        now++;
        r[i] = now;
      }
      else break;
    }
  }
  int ans = 0;
  for(int i =n -1;i>=1;--i)r[i] = min(r[i] , r[i+1]);
    for(int i =1;i<=n;++i)ans += (r[i] - i + 1);
    cout<<ans; 
}

C Sort4

这题很典。首先我们需要知道一个叫做置换环的东西。
置换环是用来求解数组排序元素间所需最小交换次数这类问题。
置换环思想:置换环将每个元素指向其排序后应在的位置,最终首位相连形成一个环(若数字在最终位置,则其自身成环),可知元素之间的交换只会在同一个环内进行,而每个环内的最小交换次数为 环上的数量-1

好了,那么我们可以先算出所有的环 , 对于每个环 , 如果环数量为4  , 那么一次操作即可完成 , 如果其大于4 , 就不止一次操作, 我们会发现,除了环内数量刚好为4 ,否则一次操作最大可以使3个数字排好序

int n , cnt;
int a[N];
bool vis[N];

void dfs(int x){
  if(vis[x])return;
  if(!vis[x]){
    vis[x] = 1;
    cnt++;
    dfs(a[x]);
  }
}

void solve(){
  cin>>n;
  
  for(int i =1;i<=n;++i){
    cin>>a[i];
    vis[i] = 0;
  }
  int ans = 0;
  int tt = 0;
  for(int i =1;i<=n;++i){
    if(vis[i])continue;
    cnt = 0;
    dfs(i);
    //找到这一组的cnt
    while(cnt > 4){
      cnt -=3 ,ans++;
    }
    if(cnt == 4)ans++;
    else if(cnt ==1)continue;
    else if(cnt == 2)tt++;
    else if(cnt == 3)ans++;
  }
  cout<<ans + (tt / 2) + (tt %2 != 0)<<endl;
}

H Yet Another Origami Problem

H-Yet Another Origami Problem_2024牛客暑期多校训练营4 (nowcoder.com)

这题,我们可以先把最小的值想象成起点,最大的值想象成终点,然后,用中间的数值,慢慢的把最小的值折过去

int n;
void solve(){
    cin>>n;
  vector<int>a(n);
  for(int i =0;i<n;++i)cin>>a[i];
  sort(all(a));
    int ans = 0;
  for (int i = 1; i < n; i++) ans = __gcd(ans, a[i] - a[i - 1]);
  cout << ans << "\n";
}

A LCT

A-LCT_2024牛客暑期多校训练营4 (nowcoder.com)

使用带权并查集,维护一下每个点在当前树的深度 , 和每个点的子树大小,当进来一个节点时,就合并,然后看 是原来的根的深度大 , 还是进来一个节点后,这个节点的子树深度+节点到根的距离大

int n;
int fa[N] , dis[N] , siz[N];

int find(int x){
  if(x  != fa[x]){
    int t = fa[x];
    fa[x] = find(fa[x]);
    dis[x] += dis[t];
  }
  return fa[x];
}

void solve(){
  cin>>n;

  for(int i =1;i<=n;++i)fa[i] = i , siz[i] = 1 , dis[i] = 0;

  for(int i =1;i<n;++i){
    int u ,v , c;
    cin>>u>>v>>c;
    //u 是 v 的父亲
    dis[v] = 1;
    fa[v] = u;
    find(v);
    siz[find(u)] = max(siz[find(u)] , siz[v]+dis[v]);
    cout<<siz[c]-1<<' ';
  }
  cout<<endl;
    
}

  • 6
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值