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;
}

 

posted @ 2020-03-28 18:42  Aya_Uchida  阅读(209)  评论(0编辑  收藏  举报