我貌似开始爆OJ了

主要是因为预处理的范围写小,以及第一次写带删除线性基,然后就调了好久/cy

如果把 \(A\) 看做一堆列向量,然后对于 \(C\) 的一个列向量 \(V\) ,以及对应列的 \(B\) 的列向量 \(B'\),由矩阵分块,可得以下式子:

\[ V = (A_1 A_2 \dots A_q) B' \]

即 \(V\) 是由 \(A\) 线性组合出的。并且 \(C\) 的每个列向量也在 \(A\) 构成的线性空间里。

固定 \(V\) 和 \(A\) ,可得 \(B\) 的数量有 \(2^{q - r}\),其中 \(r = rank(A)\)

易得,对于确定的 \(V\) 和 \(A\), \(B\) 的数量是 \(2^{s(q - r)}\)

现在需要求 \(A\) 的数量。

因为 \(A\) \(V\) 分别初等行变换 \(B\) 的解不变,所以对于秩相同的 \(V\) 都对应着相同的方案。

发现固定 \(V\) 求 \(r = r'\) 的 \(A\) 有多少比较麻烦。所以对每个固定的 \(A\) 求 \(V\) 的贡献,然后再除掉 \(V\) 的个数。

记 \(f_{n,m,r}\) 为 \(rank(A_{n,m}) = r\) 的方案数,显然对于一个固定的 \(n\),可以 \(O(n^2)\) DP 出来,转移只要讨论是已经被表示还是一个新的基。

枚举 \(r\) 易得 \(A\) 有 \(f_{p,q,r}\) 个,对于 \(C\) 只有 \(A\) 的基线性组合有效,所以考虑变换一下基,变为 \(A\) 的 \(r\) 个基,此时 \(C\) 的方案数不变,为 \(f_{r,s,x}\),其中 \(x = rank(C)\) (换基底就是乘上一个可逆矩阵)

此时答案很好表示

\[\textrm{Ans} = \sum_{r = x} \frac{f_{p,q,r} \times f_{r,s,x} \times 2 ^ {s(q - r)}}{f_{p,s,x}}\]

此时只要支持动态删除的线性基即可。

我们维护每个向量是被哪几个基异或出的。

考虑删除时要找个基来顶替,有两种情形:

  1. 存在一个非基被它异或过,那么直接异或不会降秩
  2. 不存在,则要找一个基,此时要找最小的那个,不然会发生比它小的基会有多个拥有相同的最高位。

实现时考虑到删除一个基的时候,那个基的位置会被异或上选择的那个基(根据异或性质)。

并且为了去掉要删除的基的贡献,同时计算新的基的贡献,发现那个要删除的会被贡献两次,即:

只要在被这个即将删除的基异或过的位置异或上我们用来顶替的那个基即可。

同时我在一开始写的时候写麻烦了,实际上不需要一个下标对应一个基,因为删除只和被哪些异或出有关。所以具体看代码。

#include <bits/stdc++.h>const int MAXN = 1010;
const int mod = 1000000007;
typedef long long LL;
void reduce(int & x) { x += x >> 31 & mod; }
int mul(int a, int b) { return (LL) a * b % mod; }
int fastpow(int a, int b) {int res = 1;while (b) {if (b & 1) res = mul(res, a);a = mul(a, a);b >>= 1;}return res;
}
typedef std::bitset<MAXN> B;
B A[MAXN], frm[MAXN];
int rnk, bse[MAXN], isb[MAXN];
int n, P, m, Q, typ;
void insert(int at, B x, int src) {static B fx; fx.reset(); fx[src] = true;isb[at] = 0;for (int i = m; i; --i) if (x.test(i)) {if (bse[i]) {x ^= A[bse[i]];fx ^= frm[bse[i]];} else {bse[i] = at;isb[at] = i;++rnk;break;}}A[at] = x, frm[at] = fx;
}
int remove(int at) {int ax = 0; isb[0] = 1001;for (int i = 1; i <= n; ++i)if (frm[i].test(at))if (isb[i] < isb[ax]) ax = i;rnk -= (bool) isb[ax];for (int i = 1; i <= n; ++i)if (i != ax && frm[i].test(at))frm[i] ^= frm[ax], A[i] ^= A[ax];if (isb[ax]) bse[isb[ax]] = 0;return ax;
}int f[MAXN][MAXN], g[MAXN][MAXN], ansl[MAXN], pow2[MAXN * MAXN];
void predo() {pow2[0] = f[0][0] = g[0][0] = 1;int ran = std::max(n, m * P);for (int i = 1; i <= ran; ++i)reduce(pow2[i] = pow2[i - 1] * 2 - mod);ran = std::max(std::max(n, m), P);for (int i = 0; i < ran; ++i)for (int j = 0; j <= i; ++j) {reduce(f[i + 1][j] += mul(f[i][j], pow2[j]) - mod);reduce(f[i + 1][j + 1] += mul(f[i][j], pow2[n] - pow2[j] + mod) - mod);reduce(g[i + 1][j] += mul(g[i][j], pow2[j]) - mod);reduce(g[i + 1][j + 1] += mul(g[i][j], pow2[m] - pow2[j] + mod) - mod);}ran = std::min(n, P);for (int i = std::min(n, m); ~i; --i) {int & ans = ansl[i] = 0;for (int x = i; x <= ran; ++x)reduce(ans += (LL) f[P][x] * g[x][i] % mod * pow2[m * (P - x)] % mod - mod);ans = mul(ans, fastpow(f[m][i], mod - 2));}
}
int main() {std::ios_base::sync_with_stdio(false), std::cin.tie(0);std::cin >> n >> P >> m >> Q >> typ;predo();B tx;for (int i = 1; i <= n; ++i) {tx.reset();for (int j = 1, t; j <= m; ++j)std::cin >> t, tx[j] = t;insert(i, tx, i);}std::cout << ansl[rnk] << '\n';while (Q --> 0) {int at, t;std::cin >> at; at ^= typ * ansl[rnk];tx.reset();for (int j = 1; j <= m; ++j)std::cin >> t, tx[j] = t;insert(remove(at), tx, at);std::cout << ansl[rnk] << '\n';}return 0;
}

转载于:https://www.cnblogs.com/daklqw/p/11508682.html

【集训队作业2018】围绕着我们的圆环相关推荐

  1. UOJ#449. 【集训队作业2018】喂鸽子

    #449. [集训队作业2018]喂鸽子 DP好题 法一:min-max容斥 处理前m个,最快吃饱的鸽子期望的时间 根据期望的定义 考虑每个方案数的概率*期望次数 枚举前m个用了x个,概率都是(1/m ...

  2. uoj#422. 【集训队作业2018】小Z的礼物

    uoj#422. [集训队作业2018]小Z的礼物 题目描述 Solution 所有礼物全部取到的方案数并不好求,因此我们考虑min−maxmin-maxmin−max容斥,转化为第一次取到集合中某一 ...

  3. 【UOJ#450】【集训队作业2018】复读机(生成函数,单位根反演)

    [UOJ#450][集训队作业2018]复读机(生成函数,单位根反演) 题面 UOJ 题解 似乎是\(\mbox{Anson}\)爷的题. \(d=1\)的时候,随便怎么都行,答案就是\(k^n\). ...

  4. UOJ#418. 【集训队作业2018】三角形

    #418. [集训队作业2018]三角形 和三角形没有关系 只要知道儿子放置的顺序,就可以直接模拟了 记录历史最大值 用一个pair(a,b):之后加上a个,期间最大值为增加b个 合并? A1+A2= ...

  5. 【集训队作业2018】喂鸽子

    我的计数还是太差了-- 这道题现在知道三种做法. 1. 直接DP 首先显然需要min-max容斥(不知道请百度),不然很难算. 显然对于大小相同的集合答案一样,问题转化为求 \(f_c\) 即 \(c ...

  6. 【集训队作业2018】复读机

    即使是一道菜题,也掩盖不了窝生成函数弱的事实. 窝看到题目只想到了DP,还是生成函数不够熟.然后直到神仙WWJ提醒我用生成函数-- 首先是排列,那就可以写成指数型生成函数的优美形式.直接表示成exp吧 ...

  7. UOJ#449. 【集训队作业2018】喂鸽子 min-max容斥,FFT

    原文链接www.cnblogs.com/zhouzhendong/p/UOJ449.html 题解 设 f(i) 表示给 i 只鸽子喂食使得至少一只鸽子被喂饱的期望次数,先 min-max容斥 一下. ...

  8. 【集训队作业2018】复读机【指数型生成函数】【单位根反演】【二项式定理】

    传送门 单位根反演听着高级,其实没啥技术含量-- 本文是篇几乎没有证明的佛系讲解 单位根反演的式子长这样: 1n∑i=0n−1ωnik=[k∣n]\frac{1}{n}\sum_{i=0}^{n-1} ...

  9. [集训队作业2018] count(笛卡尔树,生成函数,卡特兰数)

    传送门 什么情况下两序列同构 对于两序列A[1,n],B[1,n]A[1,n],B[1,n]A[1,n],B[1,n],设fA(1,n)=pa,fB(1,n)=pbf_A(1,n)=p_a,f_B(1 ...

最新文章

  1. php设置用户头像,PHP针对多用户实现更换头像功能
  2. React redux
  3. puppet的相关介绍
  4. 一道关于CSS选择器优先级的题
  5. 北漂九年 ,雷军终于买房了:壕掷52亿元
  6. C程序设计--VC++6.0的使用(常用快捷键)
  7. ODA(Open Design Alliance)介绍
  8. 新西兰计算机科学专业排名,2020年新西兰计算机科学专业排名榜
  9. 小朋友把游戏藏在计算机里,给两、三岁宝宝的60个超简单家庭早教游戏
  10. 软件工程实践2017——软件产品案例分析
  11. 江苏电信用户将体验iPhone6s的极速4G+网络
  12. 7-4 输出两行短句 (10分)
  13. php检测硬件代码,查看“硬件设置”的源代码
  14. k8s1.20二进制安装
  15. 使用 flying-saucer-pdf 实现html转换pdf补充
  16. 网络云存储技术Windows server 2012 (项目十 基于NTFS权限(ADLP原则)的文件共享服务的配置与管理)
  17. 如何从为知笔记迁移到有道云笔记
  18. LDAP应用:OpenLDAP集成到Jumpserver
  19. Java温故而知新-程序逻辑结构
  20. 十八、通过Sqoop2-Shell将HDFS中的数据导出到MySQL

热门文章

  1. Swipe JS – 移动WEB页面内容触摸滑动类库
  2. java 常用接口的实现--compareable
  3. Ubuntu下安装OpenGL/Glut库
  4. HLS-Demo IOS 视屏直播样例
  5. 几个视频中行为识别的底层特征及代码
  6. STM32F407的时钟配置
  7. 闭环思维之follow through和及时反馈
  8. Semver(语义化版本号)扫盲
  9. 《中国人工智能学会通讯》——11.51 基于幻象技术的异质人脸图像合成
  10. 美国会议员提出“漏洞披露法案” 仍考虑非中立实体授权