给你一个 \(n\times n\) 的矩阵 \(a\),每个位置有一个数或者 \(-1\),你要选择一些位置,满足:
- 每行每列都有且仅有一个被选中的位置。
- 不能选 \(-1\) 所在的位置。
记你选的数的和为 \(S\),对于每个 \(i=0,1,\cdots,m-1\),询问是否存在一种合法方案使得 \(S \equiv i \pmod m\)。
首先发现这个东西长得很像积和式,只是题目中的运算是求和。
因此我们可以考虑将数放到指数上,这样就可以直接套积和式,我们考虑一个多项式的形式。
(其中 \(p\) 是一个长为 \(n\) 的排列)
那么我们只需要在最后检查 \(f(x)\bmod x^m-1\) 的对应次项的系数是否为 \(0\) 即可得知答案。
然而众所周知地,积和式无法在多项式时间内计算,但是我们知道,行列式与积和式长得十分相似:
(其中 \(f(p)\) 表示排列 \(p\) 的逆序对数)
但是如果我们直接套行列式,可能出现一个问题,就是负系数的项把正系数的项抵消了。
解决方法就是我们给每个位置赋一个随机的权值。
(\(c\) 是随机出来的权值)
这样就可以有效减少错误率。
不幸的是,当我们分析时间复杂度时会发现时间复杂度是 \(n^3\times (nm)^2=O(n^7)\) 的。
边乘边取模可以将时间复杂度降到 \(O(n^5)\),但仍然无法通过。
我们考虑优化掉多项式。
(下文记 \(m\) 次单位根的 \(i\) 次方为 \(w_i\))
我们会注意到,单位根 \(w_i\) 的 \(m\) 次方 \((w_i)^m\) 总是等于 \(1\)。
因此假如我们将 \(w_i\) 代入 \(f(x)\),就相当于自动对 \(x^m-1\) 取模。
所以我们将每一个 \(m\) 次单位根代入 \(f(x)\),最后直接插值,就可以得到原来的多项式。
这个题到这里就做完了,时间复杂度 \(O(n^4)\)。
但是如果直接使用浮点数存复数,不仅精度容易爆,还跑得慢容易被卡场。
所以我们考虑将整个多项式 \(f(x)\) 对一个大素数 \(p\) 取模,只需要在本地提前打好素数和对应的原根表即可。
另外,mxz在赛时使用模拟退火通过了此题,让我们 /bx 他。 /bx/bx/bx
具体方法是以 \(-1\) 的个数为指标,在最小化它的过程中记录途中的和的出现情况。
为什么我的模拟退火没过过题,这不公平