标签:main open const get print lan 预处理 记录 $*
网址: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;
}
Gym100851A Adjustment Office 思维+模拟
标签:main open const get print lan 预处理 记录 $*
原文地址:https://www.cnblogs.com/Aya-Uchida/p/12588727.html