#1286 : 子矩阵求和

来源:互联网 发布:午觉睡多久最健康知乎 编辑:程序博客网 时间:2024/06/06 07:10
/****************************************************************************************************************
*                 Author: Wang Jizhong
*                  Time:2016-4-11
*****************************************************************************************************************/


/*******************************************************************************************************************
* 问题:给定一个无限矩阵A,如下图所示,其中Aij=min(i,j)  
*            1 1 1 1 1 1 1 1 1
*            1 2 2 2 2 2 2 2 2
*            1 2 3 3 3 3 3 3 3
*            1 2 3 4 4 4 4 4 4
*            1 2 3 4 5 5 5 5 5  ... y
*            1 2 3 4 5 6 6 6 6
*            1 2 3 4 5 6 7 7 7
*            1 2 3 4 5 6 7 8 8
*            1 2 3 4 5 6 7 8 9
*                  ⋮           ⋱
*                  x
* 希望你从中找到一个N*M的子矩阵,使得子矩阵中元素的和是K的整数倍  
*  如果不存在这样的子矩阵,输出-1;否则输出子矩阵左上角元素的下标x和y。如果存在多个满足条件的子矩阵,输出x+y最小的一个;
* 如果仍有多个,输出其中x最小的一个。  
***********************************************************************************************************************/
/**********************************************************************************************************************
*  实现思路: 过程中矩阵元素和以 所有(元素矩阵和)%K来表示;
*       假设存在N*M矩阵,左上角坐标为(x,y),则可认为左上角为(x-y,0)或者(0,y-x)沿着右下方向平移y步得到。
*      从左上角到向右下角平移1次,会导致矩阵中每个元素加1,导致平移后的矩阵元素和是(原来N*M矩阵元素和+N*M)%K,连续平移M次的结果与原来矩阵元素的结果相同,
* 故可把平移很多次的平移转化为0~K-1的平移,可以维持一个vector来保存平移n次的余数的变化,即:k*N*M%K,-1表示不可能得到这个数值
*     然后从左上角向下遍历,假设需要需求的矩阵式m*n,可从矩阵对称性知左上角坐标分别为(n-1,1)和(n,1)的n*m矩阵式相同的,故只考虑n次遍历即可,
* 在每次遍历中,我们得到矩阵的元素和,求的还差多少使得矩阵元素和为0,即为K的整数倍,然后根据vector查找平移多少步,消去那差值,如果为-1,代表不存在。
* 然后对列进行相同的遍历和查找,得到最终的结果.
************************************************************************************************************************/
//包含的库文件
#include<iostream>
#include<vector>
using namespace std;
// 定义基本类型
typedef long long int64;




vector<int> need;


int N, M, K, ansX, ansY;


// 更新坐标
void Update(int x, int y) {
if (ansX == -1)ansX = x, ansY = y;
else if (ansX + ansY > x + y) ansX = x, ansY = y;
else if (ansX + ansY == x + y && x < ansX) ansX = x,ansY = y;
}


// 获取到第i(row)行,前j(len)列的和
int64 Getsum(int row, int len) {
if (len <= row) return ((int64)1 + len)*len / 2;
return ((int64)1 + row)*row / 2 + (int64)1 *(len - row)*row;
}


// 函数功能:寻找矩阵
void Search_matrix(int n, int m, bool tran) {
int64 sum = 0;
for (int i = 0; i <= m; i++) sum = (sum + Getsum(i, n)) % K;  // 左上角n行m列的值


// 向下遍历n行,由列数决定
for (int start = 1; start <= n; start++) {
int r = (K - sum) % K;      // 还需要多少能够达到K的整数倍
if (need[r] != -1) {
int x = need[r] + 1; int y = start + need[r];
if (tran)swap(x, y);
Update(x, y);
}
sum = ((sum - Getsum(start, n)) % K + Getsum(start + m, n) % K + K) % K;   // 加K防止产生负数对K求模;
}


}




// 功能,实现子矩阵求和是K的整数倍
void Search_pos() {


// 初始化need 数组
need.assign(K + 1, -1);
int u = 0; need[u] = 0;          
while (true) {
int nu = ((int64)1 * N * M + u) % K;
if (need[nu] != -1) break;
need[nu] = need[u] + 1;u = nu;
}
ansX = -1; ansY = -1;


Search_matrix(N, M, false);   // 行搜索
Search_matrix(M, N, true);    // 列搜索
}


// 主程序函数
int main() {
ios::sync_with_stdio(false);


int Q = 0; cin >> Q;
while (Q--) {
cin >> N >> M >> K;
Search_pos();
if (ansX == -1) cout << -1 << endl;
else cout << ansX << " " << ansY << endl;
}


return 0;
}
0 0
原创粉丝点击