SRM 514 DIV1 500pt(DP)

題目簡述spa

給定一個H×W大小的矩陣,每一個格子要麼是1~9中的一個數,要麼是".",要求你把「.」填成具體的數字(1~9),而且符合如下兩個要求:設計

  • 對於全部的整數r 和 c( 0 <= r <= H-n,0 <= c < W), 使得 F[r][c] + F[r+1][c] + ... + F[r+n-1][c] 是奇數. 
  • 對於全部的整數 r 和c(0 <= r < H,0 <= c <= W-m), 使得 F[r][c] + F[r][c+1] + ... + F[r][c+m-1] 是奇數

題解code

    咱們能夠發現F[r][c]和 F[r+n][c]的奇偶性是同樣的,一樣F[r][c]和F[c+m]也是一樣的奇偶性,那麼咱們能夠把F[r+p*n][c+q*m]的能夠放的奇數和偶數的個數統計到odd[r][c]和even[r][c]中,矩陣就壓縮成了n*m了!注意若是F[r+p*n][c+q*m]是個肯定的數,若是是奇數,那麼even[r][c]=0,反之odd[r][c]=0.blog

  這樣問題就轉化成了求n×m的矩陣,每行和每列的和都是奇數的方案數!get

  接下來咱們先預處理出每一行都是奇數和的狀態的方案數cnt[i][mask],而後再進行DP,方程是dp[i][mask1^maks2]+=dp[i-1][mask1]*cnt[i][maks2],第i-1行的列狀態數是mask1,第i行選取的行狀態是mask2,那麼造成的列狀態就是mask1^maks2,最後的答案就是dp[n][(1<<m)-1],(1<<m)-1剛好表示每一列的狀態都是奇數。這道題真是很贊,狀態設計好巧妙~~,徹底想不到啊!string

代碼:it

 1 typedef long long LL;
 2 #define MOD 1000000007
 3 LL odd[15][15], even[15][15];
 4 LL dp[15][1 << 12], cnt[15][1 << 12];
 5 class MagicalGirlLevelTwoDivOne
 6 {
 7 public:
 8     int go(int num)
 9     {
10         int ret = 0;
11         while (num)
12         {
13             ret += num & 1;
14             num >>= 1;
15         }
16         return ret;
17     }
18     int theCount(vector <string> palette, int n, int m)
19     {
20         int x = palette.size(), y = palette[0].size();
21         for (int i = 0; i < n; i++)
22             for (int j = 0; j < m; j++) odd[i][j] = even[i][j] = 1;
23         for (int i = 0; i < x; i++)
24             for (int j = 0; j < y; j++)
25             {
26                 if (palette[i][j] == '.')
27                 {
28                     odd[i % n][j % m] *= 5;
29                     odd[i % n][j % m] %= MOD;
30                     even[i % n][j % m] *= 4;
31                     even[i % n][j % m] %= MOD;
32                 }
33                 else
34                 {
35                     int num = palette[i][j] - '0';
36                     if (num % 2 == 0) odd[i % n][j % m] = 0;
37                     else even[i % n][j % m] = 0;
38                 }
39             }
40         memset(cnt, 0, sizeof(cnt));
41         for (int i = 0; i < n; i++)
42             for (int mask = 0; mask < (1 << m); mask++)
43             {
44                 int tot = go(mask);
45                 if (tot % 2 == 0) continue;
46                 cnt[i][mask] = 1;
47                 for (int j = 0; j < m; j++)
48                 {
49                     if (mask & (1 << j))
50                         cnt[i][mask] *= odd[i][j];
51                     else cnt[i][mask] *= even[i][j];
52                     cnt[i][mask] %= MOD;
53                 }
54             }
55         memset(dp, 0, sizeof(dp));
56         dp[0][0] = 1;
57         for (int i = 1; i <= n; i++)
58             for (int mask1 = 0; mask1 < (1 << m); mask1++)
59                 for (int mask2 = 0; mask2 < (1 << m); mask2++)
60                 {
61                     dp[i][mask1 ^ mask2] += (dp[i - 1][mask1] * cnt[i - 1][mask2])%MOD;
62                     dp[i][mask1 ^ mask2] %= MOD;
63                 }
64         return (int)dp[n][(1 << m) - 1];
65     }
66 };
相關文章
相關標籤/搜索