AC(加注释)

初音未来  •  21小时前


#include <bits/stdc++.h>
using namespace std;
typedef long long ll;  // 定义长整型别名,便于处理大数据量
const int N = 2e5 + 5; // 行列最大数量,满足题目约束条件

ll a[N], b[N];   // 存储每行、每列的涂色次数(a数组记录行,b数组记录列)
int c[N], d[N];  // 统计行、列涂色次数对k取模后的余数分布情况

int main() {
    // 文件输入输出重定向(根据题目要求,提交前需取消注释)
    // freopen("draw.in", "r", stdin);
    // freopen("draw.out", "w", stdout);

    int n, m, q, k;
    cin >> n >> m >> q >> k;

    // 处理q次操作:记录每行每列的涂色次数
    for (int i = 1; i <= q; i++) {
        int op, x;
        cin >> op >> x;
        if (op == 1) a[x]++; // 对第x行操作次数+1
        else         b[x]++; // 对第x列操作次数+1
    }

    // 统计行涂色次数的余数分布
    for (int i = 1; i <= n; i++) 
        c[a[i] % k]++; // 行i的涂色次数模k的余数对应c数组位置+1
    
    // 统计列涂色次数的余数分布
    for (int j = 1; j <= m; j++)
        d[b[j] % k]++; // 列j的涂色次数模k的余数对应d数组位置+1

    /* 关键数学优化:计算会被擦除的格子数量 */
    ll total = (ll)n * m;  // 所有可能的格子总数
    ll same = 0;           // 存储余数和为k的倍数的组合数(会被擦除的格子)

    // 遍历所有可能的行余数i,计算对应的列余数j=(k-i)%k
    for (int i = 0; i < k; ++i) {
        int j = (k - i) % k;      // 使得i + j ≡0 mod k
        same += (ll)c[i] * d[j];  // 累加满足条件的组合数
    }

    // 最终结果 = 总格子数 - 会被擦除的格子数
    ll ans = total - same;
    cout << ans;

    return 0;
}

评论:

请先登录,才能进行评论