Skip to content

14121: 【原4121】入阵曲

题目

题目描述

author: Ca. 原OJ链接:https://acm.sjtu.edu.cn/OnlineJudge-old/problem/4121

Description

小F画出了一个n×m的矩阵,每个格子里都有一个不超过k的正整数。小F想问问你,这个矩阵里有多少个不同的子矩形中的数字之和是k的倍数? 如果把一个子矩形用它的左上角和右下角描述为(x1, y1, x2, y2),其中x1≤x2, y1≤y2; 那么,我们认为两个子矩形是不同的,当且仅当他们以(x1, y1, x2, y2)表示时不同;也就是说,只要两个矩形以(x1, y1, x2, y2)表示时相同,就认为这两个矩形是同一个矩形,你应该在你的答案里只算一次。

Input Format

输入第一行,包含三个正整数 n, m, k。 输入接下来n行,每行包含m个正整数,第i行第j列表示矩阵中第i行第j列中所填的正整数 a[i,j]。

Output Format

输入一行一个非负整数,表示你的答案。

Sample Input

2 3 2
1 2 1
2 1 2

Sample Output

6

Data Range

100%的数据,n,m≤400,k≤10^6。

zqy2018's solution

#include <bits/stdc++.h>
#define INF 2000000000
#define modadd(x, y) (x + y >= k ? x + y - k: x + y)
using namespace std;
typedef long long ll;
int read(){
    int f = 1, x = 0;
    char c = getchar();
    while(c < '0' || c > '9'){if(c == '-') f = -f; c = getchar();}
    while(c >= '0' && c <= '9')x = x * 10 + c - '0', c = getchar();
    return f * x; 
}
int n, m, k;
int a[405][405], sum[405][405] = {0};
int cnt[1000005] = {0};
int lis[405], tot;
void init(){
    n = read(), m = read(), k = read();
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= m; ++j){
            a[i][j] = read();
            sum[i][j] = sum[i][j - 1] + a[i][j];
        }
}
void solve(){
    ll ans = 0;
    for (int i = 1; i <= m; ++i){
        for (int j = i; j <= m; ++j){
            cnt[0] = 1;
            tot = 1, lis[1] = 0;
            int sm = 0;
            for (int t = 1; t <= n; ++t){
                sm = modadd(sm, (sum[t][j] - sum[t][i - 1]) % k);
                ans += cnt[sm];
                ++cnt[sm];
                lis[++tot] = sm;
            }
            for (int i = 1; i <= tot; ++i)
                cnt[lis[i]] = 0;
        }
    }
    printf("%lld\n", ans);
}
int main(){
    init();
    solve();
    return 0;
}