SJTU OJ 1228 Matrix Sum

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 
#include 
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; iif (work[i] == 1){
            store_zero[len++] = now;
            now = 0;
        }
    }
    if (len == 0) return;//没有1;
    store_zero[len++] = ++now;
    for (int i=0; ifor (int j=i+1; j2){
            re1 += (store_zero[i] * store_zero[j]);
        }
    }
    len = 0;
    return;
}
int main()
{
    scanf("%d", &n);
    int d;
    for (int i=0; ifor (int j=0; jscanf("%d", &d);
            arr[i][j] = d%2;
        }
    }
    for (int i=0; i//从第几行开始;
        for (int j=0; j//先把这一行赋给work[];
            work[j] = arr[i][j];
        }
        count_it();
        for (int j=i+1; j//再把下面的行依次加到work[];
            for (int k=0; k2;
            }
            count_it();
        }
        for (int j=0; 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;
}

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

你可能感兴趣的:(SJTUOJ)