SJTU OJ 1228 Matrix Sum

来源:互联网 发布:淘宝上的代练 编辑:程序博客网 时间:2024/06/07 10:40

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;}

还有复杂度更低的算法,欢迎指教。

原创粉丝点击