安吉D16 T3
- 1安吉D19 T1
- 2安吉D19 T3
- 3安吉D20 模考12总结
- 4安吉D17 T3
- 5安吉D17 T4
- 6安吉D19 模考11总结
- 7安吉D15 A
- 8安吉D16 T4
- 9安吉D17 T1
- 10安吉D17 模考10总结
- 11安吉D16 T3本文
- 12安吉D16 模考9总结
- 13安吉D13 模考8总结
- 14安吉D13-T2
- 15安吉D13-T3
- 16安吉D12-T3
- 17安吉D11-B
- 18安吉D11-C
- 19安吉D11-D
- 20安吉D12 模考7总结
- 21安吉D12-T2
- 22安吉D11-A
- 23安吉D10 模考6总结
- 24安吉D10-T3
- 25安吉D10-T4
- 26安吉D8-E
- 27安吉D9-T4
- 28安吉D8-A
- 29安吉D8-B
- 30安吉D8-C
- 31安吉D8-D
- 32安吉D9 模考5总结
- 33安吉D9-T2
- 34安吉D9-T3
- 35安吉D6-T4
- 36安吉D4-G
- 37安吉D5-T2
- 38安吉D6 模考4总结
- 39安吉D6-T1
- 40安吉D6-T3
- 41安吉-开营测试 T4
- 42安吉D5 模考3总结
- 43安吉D5-T3
- 44安吉D4-A
- 45安吉D4-B
- 46安吉D4-C
- 47安吉D4:容斥原理
- 48安吉Day4-D
- 49安吉D3 模考2总结
- 50安吉D3-T1
- 51安吉D3-T2
- 52安吉D3-T4
- 53安吉D2 模考1总结
- 54安吉D2-T2
- 55安吉D1-G
- 56安吉D1-L
- 57安吉D2-T4
原题呈现
P3813 矩阵填数
题目描述
给定一个 的矩阵,矩阵的行编号从上到下依次为 ,列编号从左到右依次 .
在这个矩阵中你需要在每个格子中填入 中的某个数.
给这个矩阵填数的时候有一些限制,给定 个该矩阵的子矩阵,以及该子矩阵的最大值 ,要求你所填的方案满足该子矩阵的最大值为 .
现在,你的任务是求出有多少种填数的方案满足 个限制.
两种方案是不一样的当且仅当两个方案至少存在一个格子上有不同的数.由于答案可能很大,你只需要输出答案对 取模后的结果.
输入格式
输入数据的第一行为一个数 ,表示数据组数.
对于每组数据,第一行为四个数 .
接下来 行,每一行描述一个子矩阵的最大值 v.每行为五个整数 ,表示一个左上角为 ,右下角为 的子矩阵的最大值为 . ,
输出格式
对于每组数据输出一行,表示填数方案 mod 后的值.
输入输出样例 #1
输入 #1
23 3 2 21 1 2 2 22 2 3 3 14 4 4 41 1 2 3 32 3 4 4 22 1 4 3 21 2 3 4 4输出 #1
2876475说明/提示
对于 的数据,.
另有 的数据,.
对于 的数据,,,,.
先考虑 的情况.
此时,所有填数都没有限制,则显然,答案为 .
时呢?
此时只有一个限制矩形,设这个矩形面积为 ,则可行的方案数为:矩形外随便填,存在 种填法.矩形内则是限制每一个元素都要小于等于 ,且必须要有 存在.那么矩形内合法的方案数为每一个元素都小于等于 的方案数,减去没有元素是 的方案数(即所有元素都小于等于 的方案数).矩形外和矩形内互不干涉,故将两者方案数答案相乘即为答案.
时呢?
矩形外仍是随便填,矩形内呢?显然,只被矩形 1 包括的点需要小于等于 ,只被矩形 2 包括的点需要小于等于 ,同时被两者包括的点需要小于等于 .除此之外,还需要满足矩形 1 内存在 ,矩形 2 内存在 .这需要怎么处理呢?
定义满足上述不等条件的方案数为 .即满足:
只被矩形 1 包括的点需要小于等于 ,只被矩形 2 包括的点需要小于等于 ,同时被两者包括的点需要小于等于 .
关系的方案存在 种.而不满足矩形 1 的相等关系(即矩形 1 内存在值等于 )的有 种(此时矩形 2 的相等关系可以满足,也可以不满足),不满足矩形 2 相等关系的有 种.同时不满足两个矩形的相等关系的有 种.则根据容斥的相关知识,存在答案 的表达式:
将其扩展到 ,则若 中, 的大小为偶数,则符号为正, 的大小为奇数,则符号位负,就可以使用 项将答案计算出来.
计算一下时间复杂度:
- 用于遍历所有可能的 中的
- 用于遍历图
- 用于在确定 的 后计算答案
时间复杂度 ,需要优化.
观察到此题 很小,而 很大,当值域很大,但值的个数很小时,可以考虑离散化.
具体来说,依照限制矩形的左右端点和上下端点可以将整个网格划分成一个一个的小矩形,同时满足每一个矩形内部的所有点共享一个限制.
![[grid_paper.png]]
如上图的示意图,上图中,有两个限制矩形(标为红色),依照这些矩形的边框,绿色实线将网格图分成了 9 块,每一块中的取值限制都是相同的.
具体来说,子集枚举所有可能的集合,对于每一个集合 ,尝试计算出 ,计算时,对于每一块,我们可以通过上面的研究计算出这一块的取值上限,然后使用快速幂计算取值上限的面积次方,加和即为 ,再通过容斥公式计算出最后的答案.
离散化常用来解决值域很大,但值数很小,且只关心数与数之间相对关系的问题.离散化将值转换为该值在所有值中排名,以此减小值域.
本题用到的离散化将相同限制区域合并在一起,一同计算,这也属于离散化中的一种.
标程
#include <bits/stdc++.h>#define int long longtypedef long long ll;using namespace std;const int MOD = 1'000'000'007;const int N = 50;int h, w, m, n;int lx[N], ly[N], rx[N], ry[N], v[N], a[N][N], tx[N], ty[N];int cntx, cnty;ll ans;
int fastpow(int a, int p) { ll now = a, ans = 1; while (p > 0) { if (p & 1) { (ans *= now) %= MOD; } (now *= now) %= MOD; p >>= 1; } return ans;}
void solve() { ans = 0; cntx = cnty = 0; cin >> h >> w >> m >> n; tx[++cntx] = 1, tx[++cntx] = h + 1; ty[++cnty] = 1, ty[++cnty] = w + 1; for (int i = 1; i <= n; i++) { cin >> lx[i] >> ly[i] >> rx[i] >> ry[i] >> v[i]; tx[++cntx] = lx[i]; tx[++cntx] = rx[i] + 1; ty[++cnty] = ly[i]; ty[++cnty] = ry[i] + 1; } // 离散化 sort(tx + 1, tx + cntx + 1); sort(ty + 1, ty + cnty + 1); int nx = unique(tx + 1, tx + cntx + 1) - tx - 1; int ny = unique(ty + 1, ty + cnty + 1) - ty - 1; for (int i = 1; i <= n; i++) { lx[i] = lower_bound(tx + 1, tx + nx + 1, lx[i]) - tx; rx[i] = lower_bound(tx + 1, tx + nx + 1, rx[i] + 1) - tx; ly[i] = lower_bound(ty + 1, ty + ny + 1, ly[i]) - ty; ry[i] = lower_bound(ty + 1, ty + ny + 1, ry[i] + 1) - ty; } // 进行容斥,mask 位上为 0,表不钦定,否则表钦定不能有 v_i for (int mask = 0; mask < (1 << n); mask++) { // 先默认每一个小矩形都没有限制,可以取到 [1,m] for (int i = 1; i < nx; i++) { for (int j = 1; j < ny; j++) { a[i][j] = m; } } // 对于题中提到的小矩形,我们将其限制为 v_i / v_i-1 for (int i = 1; i <= n; i++) { // 现在正在处理第 i 个矩形 for (int x = lx[i]; x < rx[i]; x++) { for (int y = ly[i]; y < ry[i]; y++) { // 对于在第 i 个矩形内部的点(x,y),更新其上限 if ((1 << (i - 1)) & mask) { // 对应位是 1,被钦定不能有 v_i // 因此上限是 v_i-1 a[x][y] = min(a[x][y], v[i] - 1); } else { // 没有钦定,随意 a[x][y] = min(a[x][y], v[i]); } } } } ll tot = 1; // 对于上述限制,计算结果 for (int x = 1; x < nx; x++) { for (int y = 1; y < ny; y++) { ll area = 1ll * (tx[x + 1] - tx[x]) * (ty[y + 1] - ty[y]); tot = 1ll * tot * fastpow(a[x][y], area) % MOD; } } if (__builtin_popcount(mask) & 1) { tot = -tot; } (ans += (tot + MOD) % MOD) %= MOD; } cout << ans << endl;}
signed main() { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int T; cin >> T; while (T--) { solve(); } return 0;}文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!


