行路难,行路难,多歧路,今安在?长风破浪会有时,直挂云帆济沧海。|

hhhqx

园龄:1年8个月粉丝:9关注:14

题解:AT_agc059_c [AGC059C] Guessing Permutation for as Long as Possible

[AGC059C] Guessing Permutation for as Long as Possible 题解

前言

题目传送门:AGC059C Guessing Permutation for as Long as Possible

题面:问又多少种 1n 的排列 P,使得 n(n1)2 个不同询问 (i,j),你说出 pipj 那个大。不能让询问者在不提问的情况下就依据前面的回答,得到谁更大。

2n400

这篇题解题只需要使用【模板】并查集

思路

分析性质,如果 (a,b) 能直接得答案,设 pa<pb,那么在此之前必然形成了一条链 pa<pc1<pc2<pc3<<pb。可如果 pa<pc1<pc2 那么在 (a,c2) 这里就可以得到答案了,轮不到讨论 (a,b),于是我们只用讨论 (a,c2)

a,c1,c2 太麻烦,于是改为 i,k,j

如果 pi<pk,那么就只能 pk>pj。如果 pi>pk,那么就只能 pk<pj

这不正是并查集的合并操作吗?设 (d,e) 为一个节点代表 pd<pe,上面的讨论就是 (i,k)(j,k) 合并,且 (k,i)(k,j) 合并。这样一来,我们的并查集中的一个集合就表示这些条件都必须同时满足或不满足。

思路都到这里了,接下来统计方案数。如何判断答案为 0?只用看 (i,j)(j,i) 是否在同一集合,因为它们两个不可以同时成立或同时不成立。如何求答案?设有 k 个集合,呢么就有 k2 个集合对应另外 k2 个,因为 (i,j)(j,i) 不在同一个集合,于是答案为 2k2

最后时间复杂度 O(n3logn),复杂度卡在了合并这里,但是合并也是有条件的,不会跑满。

Code

#include <bits/stdc++.h>

using namespace std;
using LL = long long;

const int MAXN = 400 + 3;
const LL mod = 1e9 + 7;

int n, vis[MAXN][MAXN];
int fa[MAXN * MAXN];

int Ri(int i, int j){ // (P_i < P_j) 这一节点的编号
  return (i - 1) * n + j;
}
int Getf(int x){ return fa[x] == x ? x : fa[x] = Getf(fa[x]); }
void Merge(int x, int y){ x = Getf(x), y = Getf(y), fa[x] = y; }

int main(){
  cin >> n;
  for(int i = 1, a, b; i <= n * (n - 1) / 2; i++){
    cin >> a >> b, vis[a][b] = vis[b][a] = i;
  }
  for(int i = 1; i <= n * n; i++) fa[i] = i;
  for(int i = 1; i <= n; i++){
    for(int j = 1; j <= n; j++){
      for(int k = 1; k <= n; k++){
        if(vis[i][j] > vis[i][k] && vis[i][j] > vis[j][k]){
          Merge(Ri(i,k), Ri(j,k)); // Pi < Pk  <=>  Pj < Pk
          Merge(Ri(k,i), Ri(k,j)); // Pi > Pk  <=>  Pj > Pk
        }
      }
    }
  }
  for(int i = 1; i <= n; i++){
    for(int j = 1; j <= n; j++){
      if(i != j && Getf(Ri(i,j)) == Getf(Ri(j,i))){
        cout << 0; // 矛盾
        return 0;
      }
    }
  }
  set<int> st;
  LL ans = 1;
  for(int i = 1; i <= n; i++){
    for(int j = 1; j <= n; j++){
      if(i == j) continue;
      int f = Getf(Ri(i,j)), _f = Getf(Ri(j,i));
      if(st.find(f) == st.end()){ // set 去重
        st.insert(f), st.insert(_f), ans = ans * 2ll % mod;
      }
    }
  }
  cout << ans;
  return 0;
}

本文作者:hhhqx

本文链接:https://www.cnblogs.com/huangqixuan/p/18584541

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   hhhqx  阅读(8)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起