1957: 烏鴉坐飛機
Time Limit: 2 Sec Memory Limit: 128 MB
Submit: 83 Solved: 6
[Submit][Status][Web Board]
Description
社會我福哥,爲了揍成龍去玩了玩集合。
有
有
Input
多組測試數據
第一行一個
接下來
第
接下來
Output
每組數據輸出
Sample Input
3
3 1 2 3
3 1 2 5
1 10
4
1 3
1 5
3 5
1 10
Sample Output
Yes
Yes
No
No
HINT
因oj不支持markdown和tex.
若無法正確顯示tex數學公式,請使用google chrome瀏覽器並安裝math anywhere插件
【分析】
考慮一下數據範圍數字≤10000,集合數量≤1000,剛開始的思路是暴力標記,內存炸了,硬搜超時。。。後來看了大佬的思路應該用壓位。。。。
一個int可以存32位,那麼32*32=1024>1000,所以32個int就可以存下所有情況,那麼對讀取的每個數字x,用32個int記錄一下這個x出現在哪些集合過,然後對讀取的x,y對這32個int分別做一次與運算就可以知道是否同時存在某個集合中了,
壓位沒什麼好說的,每32個集合壓成一個int記錄
判斷的話也一樣,對對應的每一位
假設
當前a[x][i]==010100
當前a[y][i]中存在010000,那麼這兩個整數的&結果一定大於0,因爲其中有一位結果是1,也就是說只要x,y同時存在於某一個集合,那麼在那一位的&運算時結果一定1,那麼最終結果一定大於0,因爲與運算只有1&1=1…所以只有同時存在某一個集合中時運算結果纔會>0,反之如果運算結果>0,那麼x,y一定同時存在與某個集合`
#include <cstdio>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
using namespace std;
int a[10010][40];
int main()
{
int n;
while(~scanf("%d",&n))
{
memset(a,0,sizeof(a)); //清零;
for(int i=0;i<n;i++)
{
int m;
scanf("%d",&m);
for(int j=0;j<m;j++)
{
int x;scanf("%d",&x);//因爲範圍是1-1000;小於1024;所以可以用32*32的存
int pos=1<<(i%32);//右移i%32位;
a[x][i/32]|=pos;//用'|'運算符記錄%32的位數;
}
}
int q;scanf("%d",&q);
while(q--)
{
int x,y;scanf("%d%d",&x,&y);
for( int i=0;i<=32;i++)
{
//應爲只有相同位置上都是1纔會是一,而相同位置上都是一則說明在同一個集合裏面;
if(a[x][i]&a[y][i]){puts("Yes");break;}
if(i==32)puts("No");
}
}
}
return 0;
}