Conspiracy 题解
Conspiracy
一道很一眼的 2-sat
但是这个题它要计数。。。
额,那先看一下有什么性质,我们发现这个后勤组织似乎像一个完全图,而这个同谋者像一个点列,不知道怎么说,就是没有任何边连接。
我们可以从 2-sat
中搞出一个解,而我们发现其他的所有解可以通过这一个解中一个人交换组织或者两个人交换来实现。
这里证明也不难,若两个人同时从同一个组织换到另一个组织,那这两个人肯定与这个组织的要求不符,而若有两对人交换组织,那这两个人也会与要求相悖。
第一个其实很好写,第二个情况这两个交换时,必须其他的同组的人对这个人都有连边或都不连边,这取决于你所在的组织。交换的人连不连都无所谓。
这个答案可以证明是很小的因为若一个人换到另一个组织最多有 n
个方案,而第二个情况也至多有 n2 的组数,所以就不用取模。
#include <bits/stdc++.h>
using namespace std;
const int N = 1e4 + 5;
vector<int> e[N];
int p[N], n;
int vis[N], dfn[N], low[N], top, flag[N], cnt, sc, id[N], ans[N], st[N];
void tomin(int &x, int y) {
if (x > y)
x = y;
}
inline void tarjan(int rt) {
vis[rt] = 1;
dfn[rt] = low[rt] = ++cnt;
st[++top] = rt, flag[rt] = 1;
for (int i = 0; i < e[rt].size(); i++) {
int v = e[rt][i];
if (!dfn[v]) {
tarjan(v);
tomin(low[rt], low[v]);
} else if (flag[v])
tomin(low[rt], dfn[v]);
}
if (dfn[rt] == low[rt]) {
++sc;
id[rt] = sc;
int y;
do {
y = st[top--];
id[y] = sc;
flag[y] = 0;
} while (y != rt);
}
}
bitset<5005> mp[5005];
int CNT[2][5005];
int c[3];
signed main() {
scanf("%d", &n);
if (n == 2) {
cout << 2 << endl;
return 0;
}
for (int i = 1, sum, x; i <= n; i++) {
scanf("%d", &sum);
while (sum--) {
scanf("%d", &x);
mp[i][x] = 1;
}
for (int j = 1; j <= n; j++) {
if (i == j)
continue;
if (mp[i][j])
e[i + n].push_back(j);
else
e[i].push_back(j + n);
}
}
for (int i = 1; i <= 2 * n; i++)
if (!vis[i])
tarjan(i);
for (int i = 1; i <= n; i++) {
if (id[i] == id[i + n]) {
puts("0");
return 0;
}
}
for (int i = 1; i <= n; i++) ans[i] = id[i] < id[i + n];
for (int i = 1; i <= n; i++) {
if (!ans[i])
c[0]++;
else
c[1]++;
}
if (c[0] == 0) {
cout << 1;
return 0;
}
// 1 是后勤都认识,0 是同谋都不认识
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
if (ans[i] != ans[j]) {
if (ans[i] == 1) {
if (mp[i][j])
CNT[1][j]++;
} else if (!mp[i][j]) {
CNT[0][j]++;
}
}
}
}
int res = 1;
for (int i = 1; i <= n; i++) {
if (ans[i] == 0) {
if (c[0] != 1) {
if (CNT[1][i] == c[1]) {
res++;
}
}
} else {
if (c[1] != 1) {
if (CNT[0][i] == c[0]) {
res++;
}
}
}
}
for (int i = 1; i <= n; i++) {
for (int j = i + 1; j <= n; j++) {
if (ans[i] != ans[j]) {
if (ans[i] == 0) {
if (!mp[i][j])
CNT[0][j]--;
if (mp[j][i])
CNT[1][i]--;
} else {
if (mp[i][j])
CNT[1][j]--;
if (!mp[j][i])
CNT[0][i]--;
}
if (CNT[ans[i]][j] == c[ans[i]] - 1 && CNT[ans[j]][i] == c[ans[j]] - 1) {
res++;
}
if (ans[i] == 0) {
if (!mp[i][j])
CNT[0][j]++;
if (mp[j][i])
CNT[1][i]++;
} else {
if (mp[i][j])
CNT[1][j]++;
if (!mp[j][i])
CNT[0][i]++;
}
}
}
}
cout << res << endl;
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现