CCF 201512-5 矩阵 传送门
这道题看上去好像可以用变形的矩阵快速幂求解, 但是最大数据范围m = 1000,n = 100,k ≤ 1e9
, 常规的算法复杂度*O(m^3*n*logk)
*肯定是不可以了, 高达1e12级数. 但是较小的数据还是可以过掉的.
我得了50分, 过掉了较小的数据, 在百度上没有找到有谁发出100分的代码, 自己也暂时想不出正解.
这里的变形, 是矩阵元素的加法变成了xor
, 乘法变成了&
. 而我想, 正解一定和这两个变化脱不了干系.
我们来分析下复杂度, 对于每次查询, 次数有1e9
之高, 效率最高的是logK
, 那么不可省去的复杂度是n logK
, 大约3000
, 时限是1s
,所以另一个复杂度不超过mlogm
. 普通的矩阵进行一次乘法是O(n^3)
, 但这里每个元素位是0 或 1
, 而且又定义了xor
为加法,&
为乘法,所以一定是把一行当作一个数来处理的, 因为两个整数的位运算是位与位之间的运算, 而这一步, 就压缩了一个线性的复杂度. 不过至于具体的算法或者说技巧, 我并不知道.
当然, 我的思路是基于类矩阵快速幂方法的, 但是可能所谓正解, 其实是一条决然不同的路.
要拿50分很简单, 做出正解, 才是真正的大佬.
#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
using namespace std;
int matrix[1005][1005], b[1005], n, m;
int E[1005][1005], matr[1005][1005], ans[1005];
int ano[1005][1005];
char ch_matrix[1005];
void multi(int E[1005][1005], int ano[1005][1005], int matr[1005][1005])
{
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= n; ++j) {
E[i][j] = (ano[i][1] & matr[1][j]);
for (int k = 2; k <= n; ++k) {
E[i][j] ^= (ano[i][k] & matr[k][j]);
}
}
}
}
void mul(int E[1005][1005], int b[1005], int ans[1005])
{
memset(ans, 0, sizeof(ans));
for (int i = 1; i <= n; ++i) {
ans[i] = E[i][1] & b[1];
//cout << ans[i] << ' ';
for (int j = 2; j <= n; ++j) {
ans[i] ^= E[i][j] & b[j];
// cout << ans[i] << ' ';
}
//cout << endl;
//cout << "ans[" << i << "] = " << ans[i] << endl;
}
}
int main()
{
cin >> n;
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= n; ++j) {
cin >> ch_matrix[j];
matrix[i][j] = ch_matrix[j] - '0';
}
}
for (int i = 1; i <= n; ++i) {
cin >> ch_matrix[i];
b[i] = ch_matrix[i] - '0';
}
cin >> m;
for (int i = 0; i < m; ++i) {
int k;
cin >> k;
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= n; ++j) {
matr[i][j] = matrix[i][j]; // 原矩阵
}
}
memset(E, 0, sizeof(E));
for (int j = 1; j <= n; ++j) {
E[j][j] = 1; // 单位矩阵
}
while (k) {
if (k & 1) {
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= n; ++j) {
ano[i][j] = E[i][j];
}
}
multi(E, ano, matr);
}
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= n; ++j) {
ano[i][j] = matr[i][j];
}
}
multi(matr, ano, ano);
k >>= 1;
}
mul(E, b, ans);
/*cout << "---------matrix---------" << endl;
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= n; ++j) {
cout << E[i][j];
}
cout << endl;
}
cout << "ans: ";*/
for (int i = 1; i <= n; ++i) {
cout << ans[i];
}
cout << endl;
}
}