Description
Dragon loves lottery, he will try his luck every week. One day, the lottery company brings out a new form of lottery called accumulated lottery. In a normal lottery, you pick 7 numbers from N numbers. You will get reward according to how many numbers you match. If you match all 7 numbers, you will get the top prize for 1 billion dollars!!! Unlike normal lottery, an M-accumulated lottery allows you to pick M numbers from N numbers. If M is big enough, this may significantly increase your possibility to win. (Of course it cost more…)
Some people buy multiple accumulated lotteries to guarantee a higher possibility to get the top prize. Despite of this, it’s still not worthy to guarantee a top prize.Knowing this, Dragon changes his target to second tier prize. To get a second tier prize, you need to contain all of the R numbers with M numbers picked.Given N, M and R, Dragon wants to know how many M-accumulated lotteries he needs to buy, so that he can guarantee that he can get at least the second tier prize.
这个题目就是让我们找到至少需要几个彩票,能够覆盖每一个R。
然后构造的话就是C(N,R)列,C(N,M)行。。。。。。
不过对于8,5,4这个数据要15分钟才能出答案。。。。。。所以。。。。。。要打表。。。。。。(坑。。。。。。)
现在还不明白为啥要这么慢。。。。。。
打表的代码如下:
#include<iostream> #include<cstring> using namespace std; const int MaxN=100; const int MaxM=100; const int MaxNode=MaxN*MaxM; const int INF=10e8; struct DLX { int U[MaxNode],D[MaxNode],L[MaxNode],R[MaxNode],col[MaxNode]; int H[MaxN],S[MaxM]; int ans; int n,m,size; void init(int _n,int _m) { n=_n; m=_m; size=m; ans=INF; for(int i=0;i<=m;++i) { L[i]=i-1; R[i]=i+1; U[i]=D[i]=i; S[i]=0; } L[0]=m; R[m]=0; for(int i=0;i<=n;++i) H[i]=-1; } void Link(int r,int c) { col[++size]=c; ++S[c]; U[size]=U[c]; D[size]=c; D[U[c]]=size; U[c]=size; if(H[r]==-1) H[r]=L[size]=R[size]=size; else { L[size]=L[H[r]]; R[size]=H[r]; R[L[H[r]]]=size; L[H[r]]=size; } } void remove(int c) { for(int i=D[c];i!=c;i=D[i]) { L[R[i]]=L[i]; R[L[i]]=R[i]; } } void resume(int c) { for(int i=U[c];i!=c;i=U[i]) L[R[i]]=R[L[i]]=i; } bool vis1[MaxM]; int getH() { int ret=0; for(int i=R[0];i!=0;i=R[i]) vis1[i]=1; for(int i=R[0];i!=0;i=R[i]) if(vis1[i]) { ++ret; vis1[i]=0; for(int j=D[i];j!=i;j=D[j]) for(int k=R[j];k!=j;k=R[k]) vis1[col[k]]=0; //!!!!!!!!!!!!!! } return ret; } void Dance(int d) { if(getH()+d>=ans) return; if(R[0]==0) { if(d<ans) ans=d; return; } int c=R[0]; for(int i=R[0];i!=0;i=R[i]) if(S[i]<S[c]) c=i; for(int i=D[c];i!=c;i=D[i]) { remove(i); for(int j=R[i];j!=i;j=R[j]) remove(j); Dance(d+1); for(int j=L[i];j!=i;j=L[j]) resume(j); resume(i); } } }; DLX dlx; int N,M,R; int C[10][10]; void getC() { for(int i=0;i<=8;++i) C[i][0]=1; for(int i=1;i<=8;++i) for(int j=1;j<=i;++j) C[i][j]=C[i-1][j-1]+C[i-1][j]; } void numTOp(int *s,int x,int n,int m,int d) { if(m<=0) return; if(x>=C[n-1][m-1]) numTOp(s,x-C[n-1][m-1],n-1,m,d+1); else { s[0]=d; numTOp(s+1,x,n-1,m-1,d+1); } } int pTOnum(int *s1,int *s2) { int vis[10],ans1=0; memset(vis,0,sizeof(vis)); for(int i=0;i<R;++i) vis[s1[s2[i]-1]]=1; int tR=R-1; for(int i=1;i<=N && tR>=0;++i) { if(vis[i]==0) ans1+=C[N-i][tR]; else --tR; } return ans1; } void slove() { int s[10]; int ts[10],temp; dlx.init(C[N][M],C[N][R]); for(int i=0;i<C[N][M];++i) { numTOp(s,i,N,M,1); for(int j=0;j<C[M][R];++j) { numTOp(ts,j,M,R,1); temp=pTOnum(s,ts); dlx.Link(i+1,temp+1); } } dlx.Dance(0); cout<<dlx.ans<<endl; } int main() { ios::sync_with_stdio(false); int T; cin>>T; getC(); for(int cas=1;cas<=T;++cas) { cin>>N>>M>>R; cout<<"Case #"<<cas<<": "; slove(); } return 0; }
把结果保存到文件里然后再复制到一个数组就行了。。。。。。