ZOJ Monthly, June 2012 - F Choir III - zoj 3616

题目说找一个 子矩阵,里面价值最大,其中男生人数 >= b, 女生人数 >= g, 中间不能有不会唱歌的人。

这题如果关键在于 排除不会唱歌的人,思想肯定是贪心思想,想人数越多越好,男生女生不过就是在if里面多判定的一句话罢了。

为了方便理解,我画张很丑的图...

ZOJ Monthly, June 2012 - F Choir III - zoj 3616

蓝色表示我当前扫到的队员,当然他是会唱歌的。

红色表示不会唱歌的队员。

白色表示,没选择的队员。

我在扫描时,对于每一个点是一行行扫,这样的话,复杂度是 N*M*N。

先扫第当前行,也就是第4行,因为第四行上面之前的队员我都会唱歌,那我尽量全部选走。

粉色代表这次选择的队员。

ZOJ Monthly, June 2012 - F Choir III - zoj 3616

再上一行,因为有不会唱歌的队员,那我只能放弃第一列之前的所有成员。

ZOJ Monthly, June 2012 - F Choir III - zoj 3616

同理在上一行是:

ZOJ Monthly, June 2012 - F Choir III - zoj 3616

最后因为不会唱歌的队员和蓝色点成员在一列了,也就是说在这列之前是不会选成员了,即:

ZOJ Monthly, June 2012 - F Choir III - zoj 3616

扫描结束,另外其中对于子矩阵的能力值的和可以在一开始预处理掉,后面的询问就是O(1)了。

我在代码中用list[i][j] 表示当前i行,第j个队员之前离j最近的不会唱歌的队员编号。

View Code
 1 #include<cstdio>

 2 #include<iostream>

 3 #include<algorithm>

 4 #include<cstring>

 5 #include<cmath>

 6 #include<map>

 7 #include<vector>

 8 using namespace std;

 9 #define N 110

10 #define M 2010

11 #define inf 2000000000

12 typedef long long LL;

13 int sum[N][M], sboy[N][M], list[N][M];

14 int sv, sb, sg;

15 void solve(int x1, int y1, int x2, int y2) {

16     if (x1 > x2 || y1 > y2) return ;

17     sv = sum[x2][y2] - sum[x1-1][y2] - sum[x2][y1-1] + sum[x1-1][y1-1];

18     sb = sboy[x2][y2] - sboy[x1-1][y2] - sboy[x2][y1-1] + sboy[x1-1][y1-1];

19     sg = (x2-x1+1)*(y2-y1+1) - sb;

20 }

21 int main() {

22     int n, m, b, g;

23     memset(sum, 0, sizeof(sum));

24     memset(sboy, 0, sizeof(sboy));

25     memset(list, 0, sizeof(list));

26     while (scanf("%d%d%d%d", &n, &m, &b, &g) != EOF) {

27         int sex, val, ans = -1;

28         for (int i = 1; i <= n; ++i) for (int j = 1; j <= m; ++j){

29             scanf("%d%d", &val, &sex);

30             sum[i][j] = sum[i][j-1] + sum[i-1][j] -sum[i-1][j-1] + val;

31             sboy[i][j] = sboy[i][j-1] + sboy[i-1][j] - sboy[i-1][j-1];

32             if (sex == 1) sboy[i][j] ++;

33             int l = -1;

34             if (val >= 0) {

35                 list[i][j] = list[i][j-1];

36                 for (int k = i; k; --k) {

37                     l = max(l, list[k][j]);

38                     solve(k, l+1, i, j);

39                     if (sv > ans && sb >= b && sg >= g)

40                         ans = sv;

41                 }

42             }

43             else list[i][j] = j;

44         }

45         if (ans != -1) printf("%d\n", ans);

46         else printf("No solution!\n");

47     }

48     return 0;

49 }

你可能感兴趣的:(2012)