(相信来看这篇博客的人都有题面)

  T2以为可以线性递推,然后花了两个小时。然后想了两个小时T1,会了一个能过的算法。但是没时间写,sad.....比赛快结束时,发现T2模数$10^9+7$,内心mmp。

Problem A 生日礼物

题目大意

  给定一个$n\times m$的网格图,每个格子中有一个不是0就是1的数,要求对于任意$w\times h$的子矩阵的和都相等,问方案数。

  (为了简洁,各式子的范围请自行脑补)

  瞎推推不难发现对于一个格子$(x, y)$,满足$a_{x, y} + a_{x + w, y + h} = a_{x + w, y} + a_{x, y + h}$。

  移项得:

$\begin{align}a_{x, y} - a_{x + w, y} = a_{x, y + h} - a_{x + w, y + h}\end{align}$

  用归纳法能够得出对于每连续的$w + 1$行,对模$h$的剩余相同的列,这$w + 1$行中的第一行和最后一行的上的数之差相等。

2018年山东省省队集训 Round 1 Day 2简要题解

  对于上图来说就是$a - b = c - d = e - f$。

  考虑先确定前$w$行,每次在后面添加一行。显然这一行我们只用考虑前$h$个数(剩下的用式$(1)$来确定)。

  考虑每一处$(i, j)$和它上面第$w$个格子上的数的差$d$

  • 若$d = 1$,则说明$a_{i - w, j + kh} = 0 (k = 0, 1, \dots)$
  • 若$d = 0$,则什么都不能说明
  • 若$d = -1$,则说明$a_{i - w, j + kh} = 1 (k = 0, 1, \dots)$

  所以变化量能为$1,-1$的只有当这一行上纵坐标模$h$同余于它的位置上的数等于它。

  然后发现只要确定左上角的$w\times h$的矩形的状况,剩下的就能用快速幂计算。

  然后我的做法就比较沙雕了。

  $f_{s}$表示恰好包含$s$中的位置作为横着相同的格子,且将前$w$行填满的方案数。(不考虑这些格子上的数)

  这个首先需要考虑这些格子上的数,进行容斥和子集和变换,再将这些格子上的数的贡献减去。

  然后单独考虑这个矩阵中每一行的贡献,枚举$0$和$1$的数量,就可以计算贡献了。

Code

  1 #include <iostream>
  2 #include <cassert>
  3 #include <cstdlib>
  4 #include <cstdio>
  5 using namespace std;
  6 typedef bool boolean;
  7 
  8 const int Mod = 1e9 + 7;
  9 
 10 int add(int a, int b) {
 11     return ((a += b) >= Mod) ? (a - Mod) : (a);
 12 }
 13 
 14 int sub(int a, int b) {
 15     return ((a -= b) < 0) ? (a + Mod) : (a);
 16 }
 17 
 18 int mul(int a, int b) {
 19     return a * 1ll * b % Mod;
 20 }
 21 
 22 int qpow(int a, int p) {
 23     int rt = 1, pa = a;
 24     for ( ; p; p >>= 1, pa = mul(pa, pa))
 25         if (p & 1)
 26             rt = mul(rt, pa);
 27     return rt;
 28 }
 29 
 30 const int S = 1 << 16;
 31 
 32 int n, m, w, h;
 33 int f[S], bit[S];
 34 int c[5][5], sc[5][5];
 35 int d[5][5], sd[5][5];
 36 int comb[5][5] = {{1, 0, 0, 0, 0}, {1, 1, 0, 0, 0}, {1, 2, 1, 0, 0}, {1, 3, 3, 1, 0}, {1, 4, 6, 4, 1}};
 37 int invs[17];
 38 
 39 inline void init() {
 40     scanf("%d%d%d%d", &n, &m, &w, &h);
 41 }
 42 
 43 int getline(int s, int l) {
 44     int rt = (s >> l) & 1;
 45     for (int i = 1; i < w; i++)
 46         rt = (((s >> (h * i + l)) & 1) << i) | rt;
 47     return rt;
 48 }
 49 
 50 int getrow(int s, int row) {
 51     int msk = (1 << h) - 1;
 52     return s >> (h * row) & msk;
 53 }
 54 
 55 inline void solve() {
 56     d[0][0] = 1;
 57     for (int i = 0; i < 4; i++)
 58         for (int j = 0; j <= i; j++) {
 59             d[i + 1][j] = add(d[i + 1][j], d[i][j]);
 60             d[i + 1][j + 1] = add(d[i + 1][j + 1], d[i][j]);
 61         }
 62     
 63     int sl_repeat = m / h;
 64     for (int i = 0; i <= 4; i++)
 65         for (int j = 0; j <= i; j++)
 66             sd[i][j] = qpow(d[i][j], sl_repeat);
 67 
 68     bit[0] = 0;
 69     for (int i = 0; i < S; i++)
 70         bit[i] = bit[i >> 1] + (i & 1);
 71     
 72     int all = 1 << (w * h);
 73     for (int s = 0; s < all; s++) {
 74         f[s] = (1 << bit[s]);
 75         for (int l = 0; l < h; l++) {
 76             int sl = getline(s, l);
 77             int blank = w - bit[sl];
 78             int cmp = 0;
 79             boolean aflag = ((m % h) > l);
 80             for (int i = 0; i <= blank; i++)
 81                 cmp = add(mul(sd[blank][i], (aflag) ? (d[blank][i]) : (1)), cmp); 
 82             f[s] = mul(f[s], cmp);
 83         }
 84     }
 85 
 86     int size = w * h;
 87     for (int i = 0; i < size; i++)
 88         for (int j = 0; j < all; j++)
 89             if (!((j >> i) & 1))
 90                 f[j] = sub(f[j], f[j ^ (1 << i)]);
 91 
 92     for (int k = 0; k <= 4; k++)
 93         for (int c0 = 0; c0 <= k; c0++) {
 94             int c1 = k - c0, ava = min(c0, c1);
 95             int& res = c[c0][c1];
 96             for (int use = 0; use <= ava; use++) {
 97 //                res = add(res, mul(comb[c0][use], mul(comb[c1][use], fac[use])));
 98                 res = add(res, mul(comb[c0][use], comb[c1][use]));                
 99             }
100             sc[c0][c1] = qpow(res, n / w - 1);
101         }
102     
103     invs[0] = 1;
104     for (int i = 1; i <= 16; i++)
105         invs[i] = qpow(1 << i, Mod - 2);
106     for (int i = 0; i < all; i++)
107         f[i] = mul(f[i], invs[bit[i]]);
108 
109     int res = 0;
110     for (int s = 0; s < all; s++) {
111         if (!f[s])
112             continue;
113         int tmp = 1;
114         for (int r = 0; r < w; r++) {
115             int sr = getrow(s, r);
116             int spe = bit[sr], cmp = 0;
117             boolean aflag = ((n % w) > r);
118             for (int c0 = 0; c0 <= spe; c0++) {
119                 cmp = add(cmp, mul(mul(::sc[c0][spe - c0], ((aflag) ? (c[c0][spe - c0]) : (1))), comb[spe][c0]));
120             }
121             tmp = mul(tmp, cmp);
122 //            cerr << sr << " " << s << " " << r << " " << cmp << '\n';
123         }
124 //        if (tmp && f[s])
125 //            cerr << s << " " << mul(f[s], tmp) << '\n';
126         res = add(res, mul(f[s], tmp));
127     }
128     printf("%d\n", res);
129 }
130  
131 int main() {
132     init();
133     solve();
134     return 0;
135 }
Problem A

相关文章:

  • 2021-08-25
  • 2022-02-13
  • 2021-08-12
  • 2021-04-13
  • 2022-12-23
  • 2021-12-13
  • 2022-12-23
  • 2021-10-11
猜你喜欢
  • 2021-10-19
  • 2022-01-03
  • 2022-02-03
  • 2021-06-21
  • 2021-06-27
  • 2022-03-07
相关资源
相似解决方案