题目概述
给出n个可重集(元素可以重复,估计就是造数据的人懒违反一下数学里集合的定义),有q个寻问,每次询问x,y是否同时在至少一个可重集里。
解题报告
暴力想法肯定有啦,就是每个数字都开一个bool数组vis,vis[i]表示该数字是否在i集合中出现过。那么每次询问只需要判断两个数字的vis是否有交集就行了。但是这样做的效率为O(n∗q)=O(2∗1e8),并不是很可观。然后我们就会想到用bitset充当bool数组,就可以把复杂度减小为O(n∗q/32)=O(6∗1e6)了。
bitset常数较大,所以我们可以自己仿写一个bitset减小常数,自己仿写还可以把unsigned long换成unsigned long long,从而使复杂度变为O(n∗q/64)=O(3∗1e6)。
然而测试了一下自己写64位好像并没有多少快,可能是64位无符号整型自身比较慢。
示例程序
STL的bitset。
#include<cstdio>
#include<bitset>
using namespace std;
const int maxn=1000,maxs=10000;
int n,te;
bitset<maxn> S[maxs+5];
bool Eoln(char ch) {return ch==10||ch==13||ch==EOF;}
char readc()
{
static char buf[100000],*l=buf,*r=buf;
if (l==r) r=(l=buf)+fread(buf,1,100000,stdin);
if (l==r) return EOF; else return *l++;
}
int readi(int &x)
{
int tot=0,f=1;char ch=readc(),lst=ch;
while ('9'<ch||ch<'0') {if (ch==EOF) return EOF;lst=ch;ch=readc();}
if (lst=='-') f=-f;
while ('0'<=ch&&ch<='9') tot=tot*10+ch-48,ch=readc();
x=tot*f;
return Eoln(ch);
}
int main()
{
freopen("program.in","r",stdin);
freopen("program.out","w",stdout);
readi(n);
for (int i=1,x,y;i<=n;i++)
{readi(x);while (x--) readi(y),S[y][i-1]=1;}
readi(te);
while (te--)
{
int x,y;readi(x);readi(y);
if ((S[x]&S[y]).any()) printf("Yes\n"); else printf("No\n");
}
return 0;
}
自己写的64位bitset。
#include<cstdio>
#include<bitset>
using namespace std;
typedef unsigned long long ULL;
const int maxn=1000,maxs=10000,maxt=maxn/64+1;
int n,te;
struct Bitset
{
ULL num[maxt];
void set(int i) {num[i/64]|=(ULL)1<<(i%64);}
bool any() {for (int i=0;i<maxt;i++) if (num[i]) return true;return false;}
};
Bitset S[maxs+5],c;
Bitset operator & (const Bitset &a,const Bitset &b)
{for (int i=0;i<maxt;i++) c.num[i]=a.num[i]&b.num[i];return c;}
bool Eoln(char ch) {return ch==10||ch==13||ch==EOF;}
char readc()
{
static char buf[100000],*l=buf,*r=buf;
if (l==r) r=(l=buf)+fread(buf,1,100000,stdin);
if (l==r) return EOF; else return *l++;
}
int readi(int &x)
{
int tot=0,f=1;char ch=readc(),lst=ch;
while ('9'<ch||ch<'0') {if (ch==EOF) return EOF;lst=ch;ch=readc();}
if (lst=='-') f=-f;
while ('0'<=ch&&ch<='9') tot=tot*10+ch-48,ch=readc();
x=tot*f;
return Eoln(ch);
}
int main()
{
freopen("program.in","r",stdin);
freopen("program.out","w",stdout);
readi(n);
for (int i=1,x,y;i<=n;i++)
{readi(x);while (x--) readi(y),S[y].set(i-1);}
readi(te);
while (te--)
{
int x,y;readi(x);readi(y);
if ((S[x]&S[y]).any()) printf("Yes\n"); else printf("No\n");
}
return 0;
}