G[mask]是一个二进制状态,表示严格取mask这些人的实验结果算平均值的时候,有多少人的答案会被覆盖。
F[mask] = G[mask] or F[S1] or F[S2] or F[S3] ... or F[Sn],其中Si为mask的子集
这是$ 3^n $转移,显然会超时
可以把它优化成,F[mask] = G[mask] or F[P1] or F[P2] ... F[Pn],其中Pi为和Si元素个数差只为1的集合
$O(2^n)$状态,$O(n)$转移,总时间代价$ O(2^n * n) $
#include <iostream> #include <cstdio> #include <cstring> #define N (1<<22) using namespace std; int F[N],G[N]; int t[25],x[25],n,top; int siz(int S) { int r = 0; for (int j=0;j<n;j++) if ((1<<j) & S) r++; return r; } int get(int S) { int r = 0 , a = 0 , b = 0; for (int j=0;j<n;j++) if ((1<<j) & S) a+=t[j+1] , b++; int tmp = a/b; for (int j=1;j<=n;j++) if (t[j]-x[j] <= tmp && tmp <= t[j]+x[j]) r += 1<<(j-1); return r; } void solve() { top = (1<<n)-1; for (int S=1;S<=top;S++) F[S] = G[S] = get(S); for (int S=1;S<=top;S++) for (int j=0;j<n;j++) if ((1<<j) & S) F[S] = F[S] | F[S^(1<<j)]; int ans = n; for (int S=1;S<=top;S++) if (F[S] == top) ans = min(ans,siz(S)); printf("%d\n",ans); } int main() { int cas = 0; while (~scanf("%d",&n)) { for (int i=1;i<=n;i++) scanf("%d%d",&t[i],&x[i]); ++cas; printf("Case %d: ",cas); solve(); } return 0; }