递推DP 赛码 1005 Game

 

题目传送门

 1 /*
 2     递推DP:官方题解
 3         令Fi,j代表剩下i个人时,若BrotherK的位置是1,那么位置为j的人是否可能获胜
 4         转移的时候可以枚举当前轮指定的数是什么,那么就可以计算出当前位置j的人在剩下i − 1个人时的位置
 5         (假设BrotherK所处的位置是1),然后利用之前计算出的F值判定此人是否可能获胜
 6         时间复杂度为O(n3)
 7     dp[i][j] 表示有i个人,j位置的人是否可能胜利。dp[1][0] = 1;    cnt = sum (dp[n][i]);
 8     有最优化子结构,i个人可以由i-1个人的情况中每个能胜利的位置再走一步
 9     取余小技巧:0~n-1
10 */
11 #include <cstdio>
12 #include <iostream>
13 #include <algorithm>
14 #include <cstring>
15 #include <string>
16 #include <map>
17 #include <vector>
18 #include <set>
19 #include <cmath>
20 #include <queue>
21 using namespace std;
22 
23 const int MAXN = 2e2 + 10;
24 const int INF = 0x3f3f3f3f;
25 int dp[MAXN][MAXN];
26 int s[MAXN];
27 
28 int main(void)        //赛码 1005 Game
29 {
30     //freopen ("E.in", "r", stdin);
31 
32     int t, n, m;
33     scanf ("%d", &t);
34     while (t--)
35     {
36         scanf ("%d%d", &n, &m);
37         for (int i=1; i<=m; ++i)
38         {
39             scanf ("%d", &s[i]);
40         }
41         memset (dp, 0, sizeof (dp));
42         dp[1][0] = 1;
43 
44         for (int i=2; i<=n; ++i)
45         {
46             for (int j=0; j<n; ++j)
47             {
48                 if (dp[i-1][j])
49                 {
50                     for (int k=1; k<=m; ++k)
51                     {
52                         dp[i][(j + s[k]) % i] = 1;
53                     }
54                 }
55             }
56         }
57 
58         int cnt = 0;
59         for (int i=0; i<n; ++i)    if (dp[n][i])    cnt++;
60 
61         printf ("%d\n", cnt);    int x = 0;
62         for (int i=0; i<n; ++i)
63         {
64             if (dp[n][i])
65             {
66                 printf ("%d", i + 1);    ++x;
67                 if (x < cnt)    printf (" ");
68             }
69         }
70         puts ("");
71     }
72 
73     return 0;
74 }

 

posted @ 2015-05-03 15:22  Running_Time  阅读(140)  评论(0编辑  收藏  举报