P9583 题解
思路
我们首先可以考虑纯模拟(每次操作暴力枚举修改),当然这样时间复杂度是 ,肯定太慢了。
既然不能暴力枚举修改,那我们将所有修改 行的次数记为 ,将所有修改 列的次数记为 ,最后枚举每个 行 列的点,如果这个点上有颜色,则涂的次数肯定不是 的倍数,而涂的次数是 ,所以只要统计出所有满足 的点的个数即可。
但是这样还是太慢了。我们可以考虑反过来想,即所有点的个数减去不满足要求的点个数。不满足要求,就是指 。
我们设 ,如果 都为 或 ,则这个点不满足要求,我们可以定义两个桶 和 , 表示对于所有 , 的个数, 同理。根据乘法原理,所有答案就是 (当然你也可以把 的情况特殊处理)。最后别忘了答案要求的是合法个数而不是不合法个数,我们要用总数减去不合法个数。
代码
# include <bits/stdc++.h>
using namespace std;
typedef long long ll; //不开 long long 见祖宗
ll n, m, q, k, op, x, sum1[200005], sum2[200005], sum, tot1[500005], tot2[500005];
int main () {
cin >> n >> m >> q >> k;
while (q --) {
cin >> op >> x;
if (op < 2)
++ sum1[x];
else
++ sum2[x];
}
for (ll i = 1; i <= n; ++ i)
++ tot1[sum1[i] % k];
for (ll i = 1; i <= m; ++ i)
++ tot2[sum2[i] % k];
for (ll i = 1; i < k; ++ i)
sum += tot1[i] * tot2[k - i];
cout << n * m - sum - tot1[0] * tot2[0]; //总数减不合法个数
return 0;
}

浙公网安备 33010602011771号