码迷,mamicode.com
首页 > 其他好文 > 详细

Gym100851A Adjustment Office 思维+模拟

时间:2020-03-28 19:37:22      阅读:59      评论:0      收藏:0      [点我收藏+]

标签: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

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!