1 条题解
-
0
自动搬运
来自洛谷,原作者为

LYqwq
RP+=+∞ || 不拿钩 7 不改签名搬运于
2025-08-24 22:38:45,当前版本为作者最后更新于2022-06-12 21:08:39,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
题目大意
一个班级被分成 个组,每组三个人,现有一些约束:
- 某对学生必须在同一小组。
- 某对学生必须不在同一小组。
现给出分组方案,以及约束条件若干条,求有多少条约束不成立。
思路
双倍经验。
既然涉及到分组,那么我的第一反应就是并查集。
使用并查集记录学生的分组情况,然后对所有约束条件一一判断,若有不成立的条件,就计入答案。
但还有一个问题:学生的名字为字符串,不是数字。
于是就需要将这些字符串转化为数字。
考虑用
map记录所有名字的下标,如果第一次遇到某个名字 ,m[s]一定为 ,这种情况给 分配下一个未使用的下标即可。注意下标不能使用 ,否则每次都会重新分配下标。作为一个非不吸氧 A 题不可的人,我决定再考虑一下字符串哈希。
可是很多种 hash 方法都会 WA 几个点。
于是将并查集范围开到 ,试图减少 hash 冲突...
还是一片红......
最终得到,使用 BKDR hash 可过此题。
上面那篇文章中说到,
need取 比较好,那么我们就取 吧,也就是 。代码是这样的:
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; }
- 1
信息
- ID
- 7740
- 时间
- 1000ms
- 内存
- 128MiB
- 难度
- 2
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者