Sets
Time Limit: 6000/3000MS (Java/Others) Memory Limit: 128000/64000KB (Java/Others)
SubmitStatus
Problem Description
给出N个数,现在需要将这些数分成若干个不相交的集合,同时给出M个限制集合,使得划分成的集合中,不能有任何一个集合包含给出的M个集合中的任意一个。求有多少种合法的集合划分方案
Input
多组数据,每组数据 :
第一行N,M(1 <= N <= 100,0 <= M <= 10)
接下来M行,每行开始一个数TOT,表示这个禁止集合中的元素个数,接下来有TOT个数。(1 <= TOT <= N,且TOT个数都是1-N之间的正整数)
Output
每组数据,输出一行,你的答案
Sample Input
2 0 3 2 2 1 2 2 1 3 10 0
Sample Output
2 2 115975
Hint
第二个样例:
3个数的划分方案是 :
{1} {2} {3}
{1,2} {3}
{1,3} {2}
{1} {2,3}
{1,2,3}
因为划分方案中任意一组合法划分不能有一个集合包含 {1,2}或 {1,3}作为子集,所以"{1,2} {3}","{1,3} {2}", "{1,2,3}"这3种划分方案不合法,合法方案为2
1 #include <iostream> 2 #include <string.h> 3 #include <algorithm> 4 #include <math.h> 5 #include <stdio.h> 6 using namespace std; 7 8 #define MAXN 9999 9 #define MAXSIZE 10 10 #define DLEN 4 11 12 class BigNum 13 { 14 private: 15 int a[500]; //可以控制大数的位数 16 int len; //大数长度 17 public: 18 BigNum() 19 { 20 len = 1; //构造函数 21 memset(a,0,sizeof(a)); 22 } 23 BigNum(const int); //将一个int类型的变量转化为大数 24 BigNum(const char*); //将一个字符串类型的变量转化为大数 25 BigNum(const BigNum &); //拷贝构造函数 26 BigNum &operator=(const BigNum &); //重载赋值运算符,大数之间进行赋值运算 27 28 friend istream& operator>>(istream&, BigNum&); //重载输入运算符 29 friend ostream& operator<<(ostream&, BigNum&); //重载输出运算符 30 31 BigNum operator+(const BigNum &) const; //重载加法运算符,两个大数之间的相加运算 32 BigNum operator-(const BigNum &) const; //重载减法运算符,两个大数之间的相减运算 33 BigNum operator*(const BigNum &) const; //重载乘法运算符,两个大数之间的相乘运算 34 BigNum operator/(const int &) const; //重载除法运算符,大数对一个整数进行相除运算 35 36 BigNum operator^(const int &) const; //大数的n次方运算 37 int operator%(const int &) const; //大数对一个int类型的变量进行取模运算 38 bool operator>(const BigNum & T)const; //大数和另一个大数的大小比较 39 bool operator>(const int & t)const; //大数和一个int类型的变量的大小比较 40 41 void print(); //输出大数 42 }; 43 BigNum::BigNum(const int b) //将一个int类型的变量转化为大数 44 { 45 int c,d = b; 46 len = 0; 47 memset(a,0,sizeof(a)); 48 while(d > MAXN) 49 { 50 c = d - (d / (MAXN + 1)) * (MAXN + 1); 51 d = d / (MAXN + 1); 52 a[len++] = c; 53 } 54 a[len++] = d; 55 } 56 BigNum::BigNum(const char*s) //将一个字符串类型的变量转化为大数 57 { 58 int t,k,index,l,i; 59 memset(a,0,sizeof(a)); 60 l=strlen(s); 61 len=l/DLEN; 62 if(l%DLEN) 63 len++; 64 index=0; 65 for(i=l-1; i>=0; i-=DLEN) 66 { 67 t=0; 68 k=i-DLEN+1; 69 if(k<0) 70 k=0; 71 for(int j=k; j<=i; j++) 72 t=t*10+s[j]-‘0‘; 73 a[index++]=t; 74 } 75 } 76 BigNum::BigNum(const BigNum & T) : len(T.len) //拷贝构造函数 77 { 78 int i; 79 memset(a,0,sizeof(a)); 80 for(i = 0 ; i < len ; i++) 81 a[i] = T.a[i]; 82 } 83 BigNum & BigNum::operator=(const BigNum & n) //重载赋值运算符,大数之间进行赋值运算 84 { 85 int i; 86 len = n.len; 87 memset(a,0,sizeof(a)); 88 for(i = 0 ; i < len ; i++) 89 a[i] = n.a[i]; 90 return *this; 91 } 92 istream& operator>>(istream & in, BigNum & b) //重载输入运算符 93 { 94 char ch[MAXSIZE*4]; 95 int i = -1; 96 in>>ch; 97 int l=strlen(ch); 98 int count=0,sum=0; 99 for(i=l-1; i>=0;) 100 { 101 sum = 0; 102 int t=1; 103 for(int j=0; j<4&&i>=0; j++,i--,t*=10) 104 { 105 sum+=(ch[i]-‘0‘)*t; 106 } 107 b.a[count]=sum; 108 count++; 109 } 110 b.len =count++; 111 return in; 112 113 } 114 ostream& operator<<(ostream& out, BigNum& b) //重载输出运算符 115 { 116 int i; 117 cout << b.a[b.len - 1]; 118 for(i = b.len - 2 ; i >= 0 ; i--) 119 { 120 cout.width(DLEN); 121 cout.fill(‘0‘); 122 cout << b.a[i]; 123 } 124 return out; 125 } 126 127 BigNum BigNum::operator+(const BigNum & T) const //两个大数之间的相加运算 128 { 129 BigNum t(*this); 130 int i,big; //位数 131 big = T.len > len ? T.len : len; 132 for(i = 0 ; i < big ; i++) 133 { 134 t.a[i] +=T.a[i]; 135 if(t.a[i] > MAXN) 136 { 137 t.a[i + 1]++; 138 t.a[i] -=MAXN+1; 139 } 140 } 141 if(t.a[big] != 0) 142 t.len = big + 1; 143 else 144 t.len = big; 145 return t; 146 } 147 BigNum BigNum::operator-(const BigNum & T) const //两个大数之间的相减运算 148 { 149 int i,j,big; 150 bool flag; 151 BigNum t1,t2; 152 if(*this>T) 153 { 154 t1=*this; 155 t2=T; 156 flag=0; 157 } 158 else 159 { 160 t1=T; 161 t2=*this; 162 flag=1; 163 } 164 big=t1.len; 165 for(i = 0 ; i < big ; i++) 166 { 167 if(t1.a[i] < t2.a[i]) 168 { 169 j = i + 1; 170 while(t1.a[j] == 0) 171 j++; 172 t1.a[j--]--; 173 while(j > i) 174 t1.a[j--] += MAXN; 175 t1.a[i] += MAXN + 1 - t2.a[i]; 176 } 177 else 178 t1.a[i] -= t2.a[i]; 179 } 180 t1.len = big; 181 while(t1.a[len - 1] == 0 && t1.len > 1) 182 { 183 t1.len--; 184 big--; 185 } 186 if(flag) 187 t1.a[big-1]=0-t1.a[big-1]; 188 return t1; 189 } 190 191 BigNum BigNum::operator*(const BigNum & T) const //两个大数之间的相乘运算 192 { 193 BigNum ret; 194 int i,j,up; 195 int temp,temp1; 196 for(i = 0 ; i < len ; i++) 197 { 198 up = 0; 199 for(j = 0 ; j < T.len ; j++) 200 { 201 temp = a[i] * T.a[j] + ret.a[i + j] + up; 202 if(temp > MAXN) 203 { 204 temp1 = temp - temp / (MAXN + 1) * (MAXN + 1); 205 up = temp / (MAXN + 1); 206 ret.a[i + j] = temp1; 207 } 208 else 209 { 210 up = 0; 211 ret.a[i + j] = temp; 212 } 213 } 214 if(up != 0) 215 ret.a[i + j] = up; 216 } 217 ret.len = i + j; 218 while(ret.a[ret.len - 1] == 0 && ret.len > 1) 219 ret.len--; 220 return ret; 221 } 222 BigNum BigNum::operator/(const int & b) const //大数对一个整数进行相除运算 223 { 224 BigNum ret; 225 int i,down = 0; 226 for(i = len - 1 ; i >= 0 ; i--) 227 { 228 ret.a[i] = (a[i] + down * (MAXN + 1)) / b; 229 down = a[i] + down * (MAXN + 1) - ret.a[i] * b; 230 } 231 ret.len = len; 232 while(ret.a[ret.len - 1] == 0 && ret.len > 1) 233 ret.len--; 234 return ret; 235 } 236 int BigNum::operator %(const int & b) const //大数对一个int类型的变量进行取模运算 237 { 238 int i,d=0; 239 for (i = len-1; i>=0; i--) 240 { 241 d = ((d * (MAXN+1))% b + a[i])% b; 242 } 243 return d; 244 } 245 BigNum BigNum::operator^(const int & n) const //大数的n次方运算 246 { 247 BigNum t,ret(1); 248 int i; 249 if(n<0) 250 exit(-1); 251 if(n==0) 252 return 1; 253 if(n==1) 254 return *this; 255 int m=n; 256 while(m>1) 257 { 258 t=*this; 259 for( i=1; i<<1<=m; i<<=1) 260 { 261 t=t*t; 262 } 263 m-=i; 264 ret=ret*t; 265 if(m==1) 266 ret=ret*(*this); 267 } 268 return ret; 269 } 270 bool BigNum::operator>(const BigNum & T) const //大数和另一个大数的大小比较 271 { 272 int ln; 273 if(len > T.len) 274 return true; 275 else if(len == T.len) 276 { 277 ln = len - 1; 278 while(a[ln] == T.a[ln] && ln >= 0) 279 ln--; 280 if(ln >= 0 && a[ln] > T.a[ln]) 281 return true; 282 else 283 return false; 284 } 285 else 286 return false; 287 } 288 bool BigNum::operator >(const int & t) const //大数和一个int类型的变量的大小比较 289 { 290 BigNum b(t); 291 return *this>b; 292 } 293 294 void BigNum::print() //输出大数 295 { 296 int i; 297 cout << a[len - 1]; 298 for(i = len - 2 ; i >= 0 ; i--) 299 { 300 cout.width(DLEN); 301 cout.fill(‘0‘); 302 cout << a[i]; 303 } 304 } 305 BigNum dp[110][110]; 306 void init() 307 { 308 int i,j; 309 dp[0][0]=1; 310 for(i=1; i<110; i++) 311 { 312 dp[i][0]=0; 313 for(j=1; j<=i; j++) 314 dp[i][j]=dp[i-1][j]*j+dp[i-1][j-1]; 315 } 316 for(i=1; i<110; i++) 317 { 318 for(j=1; j<=i; j++) 319 dp[i][0]=dp[i][0]+dp[i][j]; 320 } 321 dp[0][0]=0; 322 } 323 int a[20][110],n,m; 324 int father[200]; 325 BigNum ans,ans1; 326 int findfa(int x) 327 { 328 return father[x] == x ? x : father[x] = findfa(father[x]); 329 } 330 void solve(int x) 331 { 332 int i,j,y,z,nm=n; 333 bool bi=0; 334 for(i=1; i<=n; i++)father[i]=i; 335 for(i=0; i<m; i++) 336 { 337 if(x&(1<<i)) 338 { 339 bi^=1; 340 if(a[i][0]==0)continue; 341 y=findfa(a[i][1]); 342 for(j=2; j<=a[i][0]; j++) 343 { 344 z=findfa(a[i][j]); 345 if(z!=y) 346 father[z]=y,nm--; 347 } 348 } 349 } 350 if(bi)ans1=ans1+dp[nm][0]; 351 else ans=ans+dp[nm][0]; 352 } 353 void work() 354 { 355 int i,j,len=(1<<m); 356 ans1=ans=0; 357 for(i=0; i<len; i++) 358 { 359 solve(i); 360 } 361 ans=ans-ans1; 362 ans.print(); 363 printf("\n"); 364 } 365 int main(void) 366 { 367 init(); 368 int i,j; 369 while(~scanf("%d%d",&n,&m)) 370 { 371 for(i=0; i<m; i++) 372 { 373 scanf("%d",&a[i][0]); 374 for(j=1; j<=a[i][0]; j++) 375 scanf("%d",&a[i][j]); 376 } 377 work(); 378 } 379 }
Sets 比赛时想错方向了。。。。 (大数不能处理负数啊)
时间: 2024-10-08 21:17:53