HDU 4979 A simple math problem.

Problem 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.
 

Input
The first line of input contains only one integer T, the number of test cases.

For each case, there’s a single line contains N, M and R(1<=R<=M<=N<=8).
 

Output
Each output should occupy one line. Each line should start with "Case #i: ", with i implying the case number. For each case, just output the result with no other leading or tailing spaces.
 

Sample Input
   
   
   
   
3 2 1 1 2 2 1 2 2 2
 

Sample Output
   
   
   
   
Case #1: 2 Case #2: 1

Case #3: 1

想不到是先用dlx重复覆盖来打表才能过的

附上一发超时代码。

#include<cstdio>
#include<vector>
#include<cmath>
#include<map>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const ll maxn = 1005;
int T, n, m, x, y, t, X, Y, tot, a[maxn], tt = 0;
map<int, int> M;

inline void read(int &ret)
{
	char c;
	do {
		c = getchar();
	} while (c < '0' || c > '9');
	ret = c - '0';
	while ((c = getchar()) >= '0' && c <= '9')
		ret = ret * 10 + (c - '0');
}

struct DLX
{
#define maxn 500005
#define F(i,A,s) for (int i=A[s];i!=s;i=A[i])
	int L[maxn], R[maxn], U[maxn], D[maxn];
	int row[maxn], col[maxn], ans[maxn], cnt[maxn];
	int n, m, num, sz;

	void add(int now, int l, int r, int u, int d, int x, int y)
	{
		L[now] = l;	R[now] = r;	U[now] = u;
		D[now] = d;   row[now] = x;  col[now] = y;
	}
	void reset(int n, int m)
	{
		num = 0x7FFFFFFF;
		this->n = n;	this->m = m;
		for (int i = 0; i <= m; i++)
		{
			add(i, i - 1, i + 1, i, i, 0, i);
			cnt[i] = 0;
		}
		L[0] = m; 	R[m] = 0; 	sz = m + 1;
	}
	void insert(int x, int y)
	{
		int ft = sz - 1;
		if (row[ft] != x)
		{
			add(sz, sz, sz, U[y], y, x, y);
			U[D[sz]] = sz; D[U[sz]] = sz;
		}
		else
		{
			add(sz, ft, R[ft], U[y], y, x, y);
			R[L[sz]] = sz; L[R[sz]] = sz;
			U[D[sz]] = sz; D[U[sz]] = sz;
		}
		++cnt[y];	++sz;
	}

	//精确覆盖
	void remove(int now)
	{
		R[L[now]] = R[now];
		L[R[now]] = L[now];
		F(i, D, now) F(j, R, i)
		{
			D[U[j]] = D[j];
			U[D[j]] = U[j];
			--cnt[col[j]];
		}
	}
	void resume(int now)
	{
		F(i, U, now)	F(j, L, i)
		{
			D[U[j]] = j;
			U[D[j]] = j;
			++cnt[col[j]];
		}
		R[L[now]] = now;
		L[R[now]] = now;
	}
	bool dfs(int x)
	{
		//if (x + A() >= num) return;
		if (!R[0]) { num = min(num, x); return true; }
		int now = R[0];
		F(i, R, 0) if (cnt[now]>cnt[i]) now = i;
		remove(now);
		F(i, D, now)
		{
			ans[x] = row[i];
			F(j, R, i) remove(col[j]);
			if (dfs(x + 1)) return true;
			F(j, L, i) resume(col[j]);
		}
		resume(now);
		return false;
	}
	//精确覆盖

	//重复覆盖
	void Remove(int now)
	{
		F(i, D, now)
		{
			L[R[i]] = L[i];
			R[L[i]] = R[i];
		}
	}
	void Resume(int now)
	{
		F(i, U, now) L[R[i]] = R[L[i]] = i;
	}
	int vis[maxn];
	int flag[maxn];
	int A()
	{
		int dis = 0;
		F(i, R, 0) vis[i] = 0;
		F(i, R, 0) if (!vis[i])
		{
			dis++;	vis[i] = 1;
			F(j, D, i) F(k, R, j) vis[col[k]] = 1;
		}
		return dis;
	}
	void Dfs(int x)
	{
		if (!R[0]) num = min(num, x);
		else if (x + A()<num)
		{
			int now = R[0];
			F(i, R, 0) if (cnt[now]>cnt[i]) now = i;
			F(i, D, now)
			{
				Remove(i); F(j, R, i) Remove(j);
				Dfs(x + 1);
				F(j, L, i) Resume(j); Resume(i);
			}
		}
	}
	//重复覆盖
}dlx;

void get(int l, int r, int now, int end, int v)
{
	if (now == end) { M[v] = ++tot; return; }
	for (int i = l; i <= r; i++)
	{
		get(i + 1, r, now + 1, end, v * 10 + i);
	}
}

void insert(int l, int r, int now, int end, int v)
{
	if (now == end) { 
		dlx.insert(tot, M[v]); 
		printf("%d ", M[v]);return;
	}
	for (int i = l; i <= r; i++)
	{
		insert(i + 1, r, now + 1, end, v * 10 + a[i]);
	}
}

void find(int l, int r, int now, int end)
{
	if (now == end) { ++tot; insert(0, end - 1, 0, t, 0); printf("\n"); return; }
	for (int i = l; i <= r; i++)
	{
		a[now] = i;
		find(i + 1, r, now + 1, end);
	}
}

int main()
{
	read(T);
	while (T--)
	{
		tot = 0;
		M.clear();
		scanf("%d%d%d", &n, &m, &t);
		get(1, n, 0, t, 0);
		dlx.reset(1, tot);
		tot = 0;
		find(1, n, 0, m);
		dlx.Dfs(0);
		printf("Case #%d: %d\n", ++tt, dlx.num);
	}
	return 0;
}


你可能感兴趣的:(HDU)