Gym100851A Adjustment Office 思维+模拟
网址:https://codeforces.com/gym/100851
题意:
给你一个$n*n$的网格图,格子$(x,y)$的值是$x+y$,有两种操作:
$R$ $c$:输出第$R$列的和,然后这一列所有的数置零。
$C$ $c$:输出第$C$行的和,然后这一行所有的数置零。
一共$q$次操作。
$n \leq 1e6,q \leq 1e5$。
题解:
这个题我们考虑先预处理出这个网格图每一行每一列的和,逐个暴力求$O(n^2)$必超时,考虑求出了第一行第一列的和,显然下一行的和为这一行的和加上$n$。$O(n)$就能递推出结果。然后考虑一次操作一。如果这一列已经空了,输出$0$即可,如果没有,先观察有多少行的和已经是$0$了,这一列的实际的和就是:原来求出的和$-$(和为$0$的行的行号的和$+$这一列的列号$*$和为$0$的行的数量),然后把这一列的和记为$0$。然后记录下来。对操作二同理。
注意:所有参加计算的值都需要$long$ $long$,否则会溢出。
AC代码:
#include <bits/stdc++.h> using namespace std; const int N = 1e6 + 5; typedef long long ll; vector<ll>rd, cd; ll rdsum, cdsum; ll rsum[N], csum[N]; int main() { freopen("adjustment.in", "r", stdin); freopen("adjustment.out", "w", stdout); ll n, q;//这里不用ll应该也可,但是不值得冒这个险 scanf("%lld%lld", &n, &q); rsum[1] = (2ll + n + 1ll) * n / 2; for (int i = 2; i <= n; ++i) rsum[i] = rsum[i - 1] + n; for (int i = 1; i <= n; ++i) csum[i] = rsum[i]; char op[2]; ll p = 0;//p不用ll会溢出 for (int i = 1; i <= q; ++i) { scanf("%s%lld", op, &p); if (op[0] == 'R') { if (!rsum[p]) printf("0\n"); else { rdsum += p; printf("%lld\n", rsum[p] - (ll)cd.size() * p - cdsum); rsum[p] = 0; rd.push_back(p); } } else if (op[0] == 'C') { if (!csum[p]) printf("0\n"); else { cdsum += p; printf("%lld\n", csum[p] - (ll)rd.size() * p - rdsum); csum[p] = 0; cd.push_back(p); } } } return 0; }