SJTU OJ 1228 Matrix Sum
这道题做法不唯一,这里只写一个我第一次做时想出来的一个方法。
首先令所有奇数为1,所有偶数为0。假定一个单行的矩阵,比如是00101100011101,数其中和为奇数的子矩阵个数。我们发现连续的0取其中不论几个都不影响奇偶。假设有n个连续的0,那么可以取0~n一共n+1种情况。当矩阵只含有第一个1时,两侧的0的取法有3*2=6种。当矩阵含有前三个1时,有3*4=12种。可以发现规律。
但是子矩阵不一定单行,所以就把位置靠下的行并到上面的某一行(不妨仍然奇数为1偶数为0),然后同上操作这一行。
下面是代码:
#include <iostream>
#include <cstdio>
using namespace std;
long long, re1 = 0, re2 = 0;//re1奇数re2偶数;
int store_zero[405];//存储每一串0的取法;
int work[405];//每次操作的那一行;
int len = 0;//实时为store_zero[]的有效长度;
int arr[405][405] = {0};
void count_it(){
int now = 0;
for (int i=0; i<n; i++){
now++;
if (work[i] == 1){
store_zero[len++] = now;
now = 0;
}
}
if (len == 0) return;//没有1;
store_zero[len++] = ++now;
for (int i=0; i<len; i++){
for (int j=i+1; j<len; j+=2){
re1 += (store_zero[i] * store_zero[j]);
}
}
len = 0;
return;
}
int main()
{
scanf("%d", &n);
int d;
for (int i=0; i<n; i++){
for (int j=0; j<n; j++){
scanf("%d", &d);
arr[i][j] = d%2;
}
}
for (int i=0; i<n; i++){//从第几行开始;
for (int j=0; j<n; j++){//先把这一行赋给work[];
work[j] = arr[i][j];
}
count_it();
for (int j=i+1; j<n; j++){//再把下面的行依次加到work[];
for (int k=0; k<n; k++){
work[k] = (work[k]+arr[j][k])%2;
}
count_it();
}
for (int j=0; j<n; j++){//work[]清零;
work[j] = 0;
}
}
re2 = n*n*(n+1)*(n+1)/4 - re1;//子矩阵总数n*n*(n+1)*(n+1)/4;
cout << re1 << ' ' << re2;
return 0;
}
还有复杂度更低的算法,欢迎指教。