「NOIP模拟赛」班服
题目描述:
要开运动会了,神犇学校的n个班级要选班服,班服共有100种样式,编号1~100。现在每个班都挑出了一些样式待选,每个班最多有100个待选的样式。要求每个班最终选定一种样式作为班服,且该班的样式不能与其他班级的相同,求所有可能方案的总数,由于方案总数可能很大,所以要求输出mod 1000000007后的答案。
输入描述:
共有T组数据。
对于每组数据,第一行为一个整数n,表示有n个班级。
2~n+1行,每行有最多100个数字,表示第i-1班待选班服的编号。
输出描述:
对于每组数据,输出方案总数 mod 1000000007后的答案。
样例输入:
2
3
5 100 1
2
5 100
2
3 5
8 100
样例输出:
4
4
数据范围:
对于30%的数据,1<=T<=3, 1<=n<=3,每班待选样式不超过10种。
对于50%的数据,1<=T<=5, 1<=n<=5,每班待选样式不超过50种。
对于100%的数据,1<=T<=10, 1<=n<=10,每班待选样式不超过100种。
题解
把班级状压一下
f[i][j]表示前i件衣服达到j状态的方案
那么显然f[i][j]+=f[i-1][j]
若班级k可以穿i这件衣服,则f[i][j]+=f[i-1][j-(1<<(k-1))]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
#include<iostream> #include<cstring> #include<cstdio> #include<cstdlib> #include<algorithm> #include<cmath> #define mod 1000000007 #define ll long long using namespace std; int read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } int bin[15]; int T,n,tot; int cnt[15]; int a[15][105]; int f[105][1025]; void dp() { f[0][0]=1; for(int i=1;i<=100;i++) for(int j=0;j<=tot;j++) { f[i][j]=f[i-1][j]; for(int k=1;k<=n;k++) if(a[k][i]&&(bin[k-1]&j)) f[i][j]=(f[i][j]+f[i-1][j-bin[k-1]])%mod; } } int main() { bin[0]=1;for(int i=1;i<=10;i++)bin[i]=bin[i-1]<<1; scanf("%d",&T); while(T--) { memset(cnt,0,sizeof(cnt)); memset(a,0,sizeof(a)); scanf("%d",&n); tot=bin[n]-1; int x;char c; for(int i=1;i<=n;i++) while(scanf("%d",&x)) { ++cnt[i];a[i][x]=1; c=getchar(); if(c=='\n')break; } dp(); printf("%d\n",f[100][tot]); } return 0; } |
Subscribe