容斥 + 矩形面积并 + 状压dp

B-Blocks_第46届ICPC亚洲区域赛(昆明)(正式赛) (nowcoder.com)

题意

给出一个矩形A \((0,0),(W,H)\), 给出 \(n\;(1<=n<=10)\) 个矩形 \((x_1,y_1),(x_2,y_2)\) (坐标分别为左下角,右上角)

每次在这 n 个矩形中等概率选择 1 个,给这个区域涂色,求能将 A 区域完全涂满的期望次数

思路

  1. 看数据范围可知可能是状压dp,且因为是期望dp,倒推

  2. 设状态 \(s\) 为已经涂过色的区域,如 101 表示第 0,2 个区域被涂过了

    \(f[s]\) 表示从 \(s\) 开始,还要期望几次能涂满 A

    转移:枚举 \(s\) 中 0 的位置 i,并且记录共有 cnt 个

    ​ \(now+=f[s|2^i]\)

    ​ \(f[s]=\frac {1}n*now+\frac {n-cnt}n*f[s]\)

  3. 现在的问题是求出 dp 的起点,即有哪些状态是已经把 A 涂满的,记为 \(f[s]=0\)

    求若干矩形的面积并是否能覆盖 A,但并集不好处理,可以先求出 \(And[s]\) 表示 \(s\) 集合的面积交,用容斥求出面积并 \(Or[s]\)

    通过 \(And[s]\) 求 \(Or[s]\) 的过程可以枚举子集,\(O(3^n)\)

代码

#include <bits/stdc++.h>
using namespace std;
#define endl "\n" typedef long long ll;
typedef pair<int, int> PII;
const int N = 10;
const int mod = 998244353;
int n;
struct Node
{
ll x1, y1;
ll x2, y2;
}a[N]; ll inv[N];
ll f[1 << N];
ll And[1 << N], Or[1 << N];
ll H, W; ll qmi(ll a, ll b)
{
ll ans = 1;
while(b)
{
if (b & 1)
ans = ans * a % mod;
b >>= 1;
a = a * a % mod;
}
return ans % mod;
} void presolve()
{
for (int i = 1; i <= n; i++)
inv[i] = qmi(i, mod - 2);
for (int s = 0; s < 1 << n; s++)
{
ll X1 = 0, Y1 = 0, X2 = W, Y2 = H;
for (int i = 0; i < n; i++)
{
if (!(s >> i & 1))
continue;
auto [x1, y1, x2, y2] = a[i];
X1 = max(X1, x1), Y1 = max(Y1, y1);
X2 = min(X2, x2), Y2 = min(Y2, y2);
}
And[s] = max(0ll, X2 - X1) * max(0ll, Y2 - Y1);
}
for (int s = 0; s < 1 << n; s++)
{
Or[s] = 0;
for (int ns = s; ns; ns = (ns - 1) & s)
Or[s] += And[ns] * (__builtin_parity(ns) ? 1 : -1);
}
} void solve()
{
ll tot = H * W;
if (Or[(1 << n) - 1] < tot)
{
cout << -1 << endl;
return;
}
for (int s = (1 << n) - 1; s >= 0; s--)
{
if (Or[s] == tot)
{
f[s] = 0;
continue;
}
ll now = n, cnt = 0;
for (int i = 0; i < n; i++)
{
if (s >> i & 1)
continue;
now = (now + f[s | (1 << i)]) % mod;
cnt++;
}
f[s] = now * inv[cnt] % mod;
}
cout << f[0] << endl;
} int main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int T;
cin >> T;
while(T--)
{
cin >> n;
cin >> H >> W;
for (int i = 0; i < n; i++)
cin >> a[i].x1 >> a[i].y1 >> a[i].x2 >> a[i].y2;
presolve();
solve();
}
return 0;
}

最新文章

  1. Angular 基础入门
  2. DataInputStream和DataOutputStream
  3. 重拾java之路之webservice
  4. Svn + tomcat + Hudson持续集成部署
  5. mysql错误代码整理
  6. 分享一个解决MySQL写入中文乱码的方法
  7. 字符串模拟赛T3
  8. thinkphp验证码点击更换js实现
  9. OpenGL5-纹理贴图
  10. 修改sublime 侧边栏 颜色 等
  11. 深入浅出Node.js (9) - 玩转进程
  12. Makefile中的wildcard和patsubst
  13. ActionSupport.getText()方法 以及 js中:&lt;s:text name=&quot;&quot; /&gt;
  14. ASP.NET Core 实战:基于 Dapper 扩展你的数据访问方法
  15. LeetCode算法题-Merge Two Binary Trees(Java实现)
  16. Linux 下安装 apache
  17. day 2 - 逻辑运算
  18. Confluence 6 从其他备份中恢复数据
  19. Ajax+Python flask实现上传文件功能
  20. cf113D. Museum(期望 高斯消元)

热门文章

  1. uniapp 打包app 引入高德地图
  2. Vue中实现自定义excel下载
  3. 官网下载CentOS系统镜像过程
  4. [C++]C++11:Function与Bind
  5. vue3实现一个抽奖小项目
  6. Docker 基础 - 2
  7. flutter flutter_screenutil Looking up a deactivated widget&#39;s ancestor is unsafe.
  8. ASCLL编码器-算术运算符_四则与取模运算
  9. .net core 删除指定路径下的所有文件以及文件夹(文件夹建议保留目录)
  10. UBUNTU18.04安装CUDA