『题解』Luogu P8403 [CCC 2022 J4] Good Groups

\(\textsf{update on 2022/6/20 发现题目链接错了,修复。}\)


题目传送门

题目大意

一个班级被分成 \(g\) 个组,每组三个人,现有一些约束:

  • 某对学生必须在同一小组。
  • 某对学生必须不在同一小组。

现给出分组方案,以及约束条件若干条,求有多少条约束不成立。

思路

双倍经验

既然涉及到分组,那么我的第一反应就是并查集。

使用并查集记录学生的分组情况,然后对所有约束条件一一判断,若有不成立的条件,就计入答案。

但还有一个问题:学生的名字为字符串,不是数字。

于是就需要将这些字符串转化为数字。

考虑用 map 记录所有名字的下标,如果第一次遇到某个名字 \(s\)m[s] 一定为 \(0\),这种情况给 \(s\) 分配下一个未使用的下标即可。注意下标不能使用 \(0\),否则每次都会重新分配下标。

但这种方法直接交上去会 TLE,吸氧才能 AC

作为一个非不吸氧 A 题不可的人,我决定再考虑一下字符串哈希。

可是很多种 hash 方法都会 WA 几个点。

于是将并查集范围开到 \(10^7\),试图减少 hash 冲突...

还是一片红......

最终得到,使用 BKDR hash 可过此题。

上面那篇文章中说到,need\(2^n-1\) 比较好,那么我们就取 \(2^6-1\) 吧,也就是 \(63\)

代码是这样的:

int hs(string s){
    unsigned int res=0;
    for(int i=0; i<s.size(); i++)
        res=(res*63)^s[i];
    return res%(int)1e7; // 最后需要mod1e7,
}

再交一发,这题就没了

代码

#include <iostream>
using namespace std;
const int N=1e5+5;
int x,y,g,ans;
string n1[N][2],n2[N][2],a,b,c;

template<class T=int>
class set{
    public:
        set(int n=1e5){f=new T[l=n+5]; clear();}
        ~set(){delete[] f;}
        T find(T x){return f[x]==x ? x : f[x]=find(f[x]);}
        void merge(T x,T y){f[find(x)]=find(y);}
        void clear(){for(int i=0; i<l; i++) f[i]=i;}
    private:
        T *f;
        int l;
};
set<int> s(1e7); // 并查集(构造函数传范围)

// 字符串哈希
int hs(string s){
    unsigned int res=0;
    for(int i=0; i<s.size(); i++)
        res=res*63+s[i]; // BKDR 哈希
    return res%(int)1e7;
    // res需要作为数组下标,为了防止哈希冲突,将数组开到了 1e7
}

int main(){
    scanf("%d",&x); // 约束 1 个数
    for(int i=1; i<=x; i++) cin >> n1[i][0] >> n1[i][1];
    scanf("%d",&y); // 约束 2 个数
    for(int i=1; i<=y; i++) cin >> n2[i][0] >> n2[i][1];
    scanf("%d",&g); // 组数
    for(int i=1; i<=g; i++){
        cin >> a >> b >> c; // a,b,c 在同一组
        s.merge(hs(a),hs(b)); // 将其合并
        s.merge(hs(a),hs(c));
    }
    for(int i=1; i<=x; i++) // 判断是否违反约束 1
        if(s.find(hs(n1[i][0]))!=s.find(hs(n1[i][1]))) ans++;
    for(int i=1; i<=y; i++) // 同上,约束 2
        if(s.find(hs(n2[i][0]))==s.find(hs(n2[i][1]))) ans++;
    printf("%d\n",ans);
    return 0;
}
posted @ 2022-06-12 21:13  仙山有茗  阅读(87)  评论(0编辑  收藏  举报