BNUOJ 51637 Quailty's Life | BZOJ 4587 推箱子
来源:互联网 发布:安卓js css本地打包 编辑:程序博客网 时间:2024/06/12 00:33
题目
https://acm.bnu.edu.cn/v3/problem_show.php?pid=51637
http://www.lydsy.com/JudgeOnline/problem.php?id=4587
题意
有一个
题解
1.一个暴力
定义
初始状态
如果
如果
答案是所有终止状态的
状态转移,只涉及加减,模运算很好套用,时间复杂度
int ans = 0, f[n + 1][m + 1];for(int i = 0; i <= n; ++i) for(int j = 0; j <= m; ++j) { if(canreach[i][j] == -1) { f[i][j] = 0; continue; } if(i == 0 && j == 0) { f[i][j] = 1; continue; } long long tmp = 0; if(i > 0 && j < m) tmp += f[i - 1][j]; if(i < n && j > 0) tmp += f[i][j - 1]; if(i > 0 && j > 0) tmp += f[i - 1][j - 1]; f[i][j] = tmp % mod; if(i == n || j == m) ans += f[i][j]; }
用于对拍
2. k=0 的情况
考虑从
设从
对应的方案数是
考虑
那么枚举
不过这个题不是求无阻碍到
但是到终止状态前的一个点是无阻碍的,枚举前一个点算贡献即可。
考虑怎么计算
由于还要枚举
3. k>0 的情况
3.1 我会容斥?
”不经过任意一个坏点的方案数“可以通过计算”至少经过其中
枚举坏点集合
看上去时间复杂度是
3.2 我会容斥!
对于每个坏点
答案也可以这么统计,算从
看上去时间复杂度是
注意坏点在终止状态上的情况。写个暴力对拍一下就可以发现问题
代码
#include <cstdio>#include <algorithm>typedef long long LL;const int maxp = 46341, maxc = 11, maxk = 11, maxe = 51;void exgcd(int a, int b, int &x, int &y){ if(!b) { x = 1; y = 0; return; } exgcd(b, a % b, y, x); y -= a / b * x;}int mod_inv(int x, int p){ int s, t; exgcd(x, p, s, t); return s < 0 ? s + p : s;}int tot, prime[maxp], fir[maxp], mod, cnt, fact[maxc], Exp[maxc], Coeff, Lim[maxc], Pw[maxc][maxe];inline void mod_dec(int &x, int y, int c = 1){ while(c--) if((x -= y) < 0) x += mod;}void init(){ Coeff = 1; for(int i = 0; i < cnt; ++i) { Exp[i] = Lim[i] = 0; Pw[i][0] = 1; }}void update(int val, int flag){ for(int i = 0; i < cnt; ++i) for( ; val % fact[i] == 0; Exp[i] += flag, val /= fact[i]); Coeff = (LL)Coeff * (flag == 1 ? val : mod_inv(val, mod)) % mod;}int query(){ int ret = Coeff; for(int j = 0; j < cnt && ret; ++j) { if(!Exp[j]) continue; for( ; Lim[j] < Exp[j]; ++Lim[j]) Pw[j][Lim[j] + 1] = (LL)Pw[j][Lim[j]] * fact[j] % mod; ret = (LL)ret * Pw[j][Exp[j]] % mod; } return ret;}int calc_1(int n, int m){ if(n > m) std::swap(n, m); if(n < 0) return 0; else if(!n) return 1; int ret = 0; init(); for(int i = 1; i <= n; ++i) { update(m + i, 1); update(i, -1); } for(int i = 0; i <= n; ++i) { mod_dec(ret, mod - query()); if(i == n) break; update(n - i, 1); update(m - i, 1); update(n + m - i, -1); update(i + 1, -1); } return ret;}int calc_2(int n, int m){ if(n > m) std::swap(n, m); if(n < 0) return 0; else if(!n) return 1; int ret = 0; --n; --m; init(); for(int i = 1; i <= n; ++i) { update(m + i, 1); update(i, -1); } update(n + m + 1, 1); for(int i = 0; i <= n; ++i) { update(n + 1, -1); mod_dec(ret, mod - query(), 2); update(n + 1, 1); update(m + 1, -1); mod_dec(ret, mod - query(), 2); update(m + 1, 1); update(n + m + 1 - i, -1); mod_dec(ret, query()); if(i == n) break; update(n - i, 1); update(m - i, 1); update(i + 1, -1); } return ret;}int t, n, m, k, f[maxk], ans;std::pair<int, int> lim[maxk];int main(){ for(int i = 2; i < maxp; ++i) { if(!fir[i]) prime[tot++] = fir[i] = i; for(int j = 0, k; (k = i * prime[j]) < maxp; ++j) { fir[k] = prime[j]; if(fir[i] == prime[j]) break; } } scanf("%d", &t); while(t--) { scanf("%d%d%d%d", &n, &m, &k, &mod); int tmp = mod; cnt = 0; for(int i = 0; i < tot && prime[i] * prime[i] <= tmp; ++i) if(tmp % prime[i] == 0) for(fact[cnt++] = prime[i]; tmp % prime[i] == 0; tmp /= prime[i]); if(tmp > 1) fact[cnt++] = tmp; for(int i = 0; i < k; ++i) scanf("%d%d", &lim[i].first, &lim[i].second); std::sort(lim, lim + k); k = std::unique(lim, lim + k) - lim; for(int i = 0; i < k; ++i) { int &ai = lim[i].first, &bi = lim[i].second; if(ai < n && bi < m) { f[i] = calc_1(ai, bi); for(int j = 0; j < i; ++j) { int &aj = lim[j].first, &bj = lim[j].second; int coeff = calc_1(ai - aj, bi - bj); if(coeff) f[i] = (f[i] - (LL)coeff * f[j]) % mod; } } else { f[i] = calc_1(ai - 1, bi - 1); if(ai < n) mod_dec(f[i], mod - calc_1(ai, bi - 1)); if(bi < m) mod_dec(f[i], mod - calc_1(ai - 1, bi)); for(int j = 0; j < i; ++j) { int &aj = lim[j].first, &bj = lim[j].second; int coeff = calc_1(ai - 1 - aj, bi - 1 - bj); if(ai < n) mod_dec(coeff, mod - calc_1(ai - aj, bi - 1 - bj)); if(bi < m) mod_dec(coeff, mod - calc_1(ai - 1 - aj, bi - bj)); if(coeff) f[i] = (f[i] - (LL)coeff * f[j]) % mod; } } } ans = calc_2(n, m); for(int i = 0; i < k; ++i) { int coeff = calc_2(n - lim[i].first, m - lim[i].second); if(coeff) ans = (ans - (LL)coeff * f[i]) % mod; } if(ans < 0) ans += mod; printf("%d\n", ans); } return 0;}
- BNUOJ 51637 Quailty's Life | BZOJ 4587 推箱子
- quailty's Contest #1 题解
- 推箱子
- 推箱子
- 推箱子
- 推箱子
- 推箱子
- 推箱子
- 推箱子
- 推箱子
- 推箱子
- 推箱子
- 推箱子
- 【推箱子】
- 推箱子
- 推箱子
- 推箱子
- 推箱子
- HDU1102 Constructing Roads
- CodeForces 585D Present for Vitalik the Philatelist(容斥原理+gcd)
- ionic安卓默认的tabs修改为底部显示
- LeetCode|Add and Search Word - Data structure design
- 135_Service给Activity发消息
- BNUOJ 51637 Quailty's Life | BZOJ 4587 推箱子
- leetcode.84. Largest Rectangle in Histogram
- ftp安装
- Spark 2.0技术预览:更容易、更快速、更智能
- w3schools网站的HTML教程之HTML基础
- 136_android布局优化措施
- Linux的目录结构整理
- 欢迎使用CSDN-markdown编辑器
- 在ubuntu下安装vmware tools