题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6778
解题思路:
二分答案,用f[i][j]表示存不存在到了第i天,二进制表示为j的尾号组(对于某一个尾号,被限制为1,不被限制为0)已经被限制过的情况;对于第i+1天,枚举剩下尾号的子集,判断可行不可行,即可进行转移。
#include<bits/stdc++.h> using namespace std; char s[10]; int c[10]; bool f[10][1<<10]; bool judge(int k, int s) { for(int i = 0; i <= 9; i++) if((k>>i) & 1) s-=c[i]; return s <= 0; } bool check(int mid) { int s = 0; for(int i = 0; i <= 9; i++) s+=c[i]; s -= mid; memset(f, 0, sizeof(f)); for(int i = 0; i < (1<<10); i++) if(judge(i,s)) f[0][i] = 1; for(int i = 1; i <5; i++) { for(int j = 0; j < (1<<10); j++) //枚举集合 { for(int k = j, l; k; k = (k-1)&j) //枚举子集 { l = j^k; if(!f[i-1][l] || !judge(k,s)) continue; f[i][j] = 1; break; } } } for(int i = 0; i < (1 << 10); i++) if(f[4][i]) return 1; return 0; } int bsearch_1(int l, int r) { while (l < r) { int mid = l + r >> 1; if (check(mid)) r = mid; else l = mid + 1; } return l; } int main() { int t; scanf("%d",&t); while(t--) { int n; scanf("%d",&n); for(int i = 1; i <= n; i++) { scanf("%s",s); c[s[4]-'0']++; } printf("%d\n",bsearch_1(1, n) ); } }