题目背景
小 L 喜欢逻辑推理。
一天,他在一本由英国哲士沃·协德编写的《我也不知道为什么要叫这个名字的一本有关逻辑学的书》中翻到了一道奇特的问题,但他并不会做。他知道你善于用程序解决问题,于是决定让你来帮助他完成这些问题。
题目描述
这是一道有 n 个选项的选择题,每个选项的内容都很独特。第 i 个选项的内容的形式如下:
- 第 ai 个选项是正确/错误的
小 L 认为这种题目的答案不一定是唯一的,所以他想问题这道题有多少种合法的答案(可以全部正确或全部错误)。他还想问你这么多答案中,正确选项最多和最少的答案分别有多少个正确选项。
当然,如果这道题不存在合法的答案,你可以直接回答小 L No answer
。
输入格式
第一行有一个正整数 n,表示选项个数。
接下来 n 行,每行有两个整数 ai,opti,描述一个选项。其中当 opti=1 时,表示这个选项的内容为 第 ai 个选项是正确的;当 opti=0 时,表示这个选项的内容为 第ai 个选项是错误的。
输出格式
如果没有答案满足这道选择题,输出No answer
。
否则输出三行,每行一个正整数,分别为合法答案数及正确选项最多和最少的答案分别有多少个正确选项。其中合法答案数要对 998244353 取模。
输入输出样例
输入 #1
4 2 1 4 0 1 1 2 0
输出 #1
2 3 1
输入 #2
10 4 1 7 0 2 0 3 1 7 1 5 0 9 1 10 1 8 0 1 1
输出 #2
No answer
说明/提示
对于样例一,一共有下面 2 种正确答案:
- 第 1,2,3 个选项是正确的。
- 第 4 个选项是正确的。
其中正确选项最多的答案有 33 个选项正确,正确选项最少的答案有 11 个选项正确。
数据范围
对于 10% 的数据,n≤10。
对于 30%的数据,n≤100。
对于 60%的数据,n≤103。
对于 100% 的数据,n≤106,1≤ai≤n,i≠ai,opti∈{0,1}。
#include <bits/stdc++.h>
using namespace std;
int f[1000005],r[1000005],num[1000005][5];
int fa(int x)
{
if(f[x]==x)return f[x];
int t=f[x];
f[x]=fa(f[x]);
r[x]=(r[t]+r[x])%2;
return f[x];
}
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)f[i]=i;
for(int i=1;i<=n;i++)
{
int a,opt;
scanf("%d%d",&a,&opt);
if(fa(i)!=fa(a))
{
int tmp=fa(i);
f[fa(i)]=fa(a);
r[tmp]=(r[i]+opt+1+r[a])%2;
}else
{
if((r[i]+r[a])%2!=(opt+1)%2)
{
printf("No answer");
return 0;
}
}
}
for(int i=1;i<=n;i++)
{
if(fa(i)==i)
{
num[i][0]++;
}else
{
num[fa(i)][r[i]]++;
}
}
int maxans=0,minans=0,tot=1;
for(int i=1;i<=n;i++)
{
if(fa(i)==i)
{
tot=tot*2%998244353;
maxans+=max(num[i][1],num[i][0]);
minans+=min(num[i][1],num[i][0]);
}
}
printf("%d\n%d\n%d\n",tot,maxans,minans);
return 0;
}