Counting(模拟)

74 阅读2分钟

H-Counting

原题题面

image.png

题目描述

一座长宽为 n,mn,m 的城市,有编号为 1k1\sim kkk 个人漫步,现在给出他们的起始位置和接下来 tt 秒的移动方向,每次移动用 L,R,U,DL,R,U,D 分别代表向左,右,上,下移动至相邻的一格。问在 0t0\sim t 秒中每秒有多少对人可以相见。题目保证每一秒中 kk 个人均在城市的范围内。

数据格式

image.png

输入样例

2 2 2 1
1 1
2 2
R
U

输出样例

0
1

题目分析

这是一道 模拟 题。

对于题目中的每一秒,如果我们能统计出每个单元格内含有的人数,自然可以计算出见面的人的对数。首先考虑暴力做法,记录每个人的初始位置和下一秒的去向,每一秒对城市内的所有单元格进行逐一遍历,并依次累加答案。由题目数据,显然会超出时间限制。

然后我们来考虑优化,假设 t1t-1 秒的答案为 resres,我们依次对 tt 秒的每个人进行分析,假设人物 aatt 秒时到达单元格 (i,j)(i,j),此时 (i,j)(i,j) 上已经有 xx 个人。那么 aa 的到达对这一秒答案的贡献是 xx,因为他会与 xx 个人中的每一个人均见面。同时我们假设人物 aa 是由单元格 (n,m)(n,m) 而来,在他离开后,单元格 (n,m)(n,m) 仍有 yy 个人,那么 aa 的离开对这一秒答案的贡献是 y-y,因为他会与 yy 个人中的每一个人减少一次见面。依次枚举。

对于优化后的方案,我们可以发现每一秒仅需枚举每一个人及统计他的去向和起末位置的人数变化,复杂度降到 O(Tk)O(Tk)

Accept代码

#include <bits/stdc++.h>

using namespace std;

const int N = 2010;

int g[N][N];
string s[N];
int res;

void add(int x, int y)
{
    res += g[x][y];
    g[x][y] ++;
}

void del(int x, int y)
{
    g[x][y] --;
    res -= g[x][y];
}
    
int x[N], y[N];
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    
    int n, m, k, t;
    cin >> n >> m >> k >> t;
    for (int i = 0; i < k; i ++) cin >> x[i] >> y[i];
    for (int i = 0; i < k; i ++) add(x[i], y[i]);
    cout << res << "\n";
    for (int i = 0; i < k; i ++) cin >> s[i];
    for (int i = 0; i < t; i ++)
    {
        for (int j = 0; j < k; j ++)
        {
            char op = s[j][i];
            del(x[j], y[j]);
            if (op == 'U') x[j] --;
            else if (op == 'D') x[j] ++;
            else if (op == 'L') y[j] --;
            else y[j] ++;
            add(x[j], y[j]);
        }
        cout << res << "\n";
    }
    return 0;
}