主角光环
题目大意:
有n个人挨打,每个人有一个互不相同编号。
对方事先告诉你它每次会打哪些编号的人。
每次我们可以保护所有已经被打过的人或者保护一个没被打过的人。
如果一个人被打两次就会死掉。
有两个人因为体质特殊,一次都不能打。
问在没有人牺牲的情况下,有多少种安排这两个人编号的方法(两个人交换算同一种)。
思路:
乱搞。
枚举每一个人,然后倒序枚举每一轮打人的情况。
对于每个人,在保证它不会被打的情况下维护已经被打的人的集合。
方便起见,假装这个人已经被打过一次。
对于每一轮打人的情况,统计有多少个人已经被打过一次,设被打一次的人数为cnt。
如果cnt=0,没有人被打过,那么保护所有将要被打的人。
如果cnt=1,自己被打过一次,就先保护自己,让剩下来所有人挨打。
如果cnt>1,除自己以外还有人已经被打过,如果保护自己,那么另一个人就得牺牲;如果保护另一个人,自己只能被打一次。所以不管怎样都得死,这个位置不适合特殊体质。
最后枚举每两个位置,判断一下两个是否都适合特殊体质,以及因为这两个人而被挨打一次的人有没有交集。
如果有交集,那么就相当于交上面的人被打了两次。
1 #include<cstdio> 2 #include<cctype> 3 #include<vector> 4 #include<bitset> 5 inline int getint() { 6 register char ch; 7 while(!isdigit(ch=getchar())); 8 register int x=ch^'0'; 9 while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0'); 10 return x; 11 } 12 const int N=1001,M=10001; 13 std::vector<int> kill[M]; 14 std::bitset<N> b[N]; 15 bool hurt[N]; 16 int main() { 17 const int n=getint(),m=getint(); 18 for(register int i=1;i<=m;i++) { 19 for(register int k=getint();k;k--) { 20 kill[i].push_back(getint()); 21 } 22 } 23 for(register int i=1;i<=n;i++) { 24 b[i].set(i); 25 for(register int j=m;j;j--) { 26 int cnt=0; 27 for(register unsigned k=0;k<kill[j].size();k++) { 28 cnt+=b[i][kill[j][k]]; 29 } 30 if(!cnt) continue; 31 if(cnt==1) { 32 for(register unsigned k=0;k<kill[j].size();k++) { 33 b[i].set(kill[j][k]); 34 } 35 } else { 36 hurt[i]=true; 37 break; 38 } 39 } 40 } 41 int ans=0; 42 for(register int i=1;i<=n;i++) { 43 if(hurt[i]) continue; 44 for(register int j=i+1;j<=n;j++) { 45 if(hurt[j]) continue; 46 if((b[i]&b[j]).none()) ans++; 47 } 48 } 49 printf("%d\n",ans); 50 return 0; 51 }