首页 > 试题广场 >

#include us...

[单选题]
#include <iostream>
#include <map>

using namespace std;
int main() {
    int n;
    scanf("%d", &n);
    map<int, int> xs;
    map<int, int> ys;
    map<pair<int, int>, int> zs;
    long long ans = 0;
    for (int i = 0; i < n; i++) {
        int x, y;
        scanf("%d %d", &x, &y);
        ans += (xs[x]++);
        ans += (ys[y]++);
        ans -= (zs[make_pair(x, y)]++);
    }
    cout << ans << endl;
    return 0;
}
输入:
6
0 0
0 1
0 2
-1 1
0 1
1 1
则上述程序输出为()
  • 9
  • 10
  • 11
  • 12
ans:对于x加的是0-1-2-0-3-0 ans:对于y加的是0-0-0-1-2-3 ans:对于(x,y)减的是0-0-0-0-1-0 所以最后结果就是12-1=11
发表于 2019-10-20 10:36:24 回复(3)

不会就选C哈哈

发表于 2019-08-23 00:28:57 回复(2)
没明白 xs[]里有数吗  上来就++
发表于 2021-03-08 09:32:36 回复(1)
这题目,用C的读取,C++的输出真是烧啊。----槽点

最笨的方法直接丢IDE结果为11
                                                          等号右边
ans += (xs[x]++);                           1  1  1  0  1  2
ans += (ys[y]++);                           1  2  3  2  2  2
ans -= (zs[make_pair(x, y)]++);     1  1  1  1  2  1【解析如下】

zs[make_pair(x,y)]这里是记录点出现的次数
(0,1)-------1
(0,1)-------1
(0,2)-------1
(-1,1)----1
(0,1)-------2
(1,1)-------1


make_pair ()构造一个pair()
 
18-7=11

-----C

发表于 2019-10-07 14:41:13 回复(2)
都加了括号了,还是不能先自增啊…
发表于 2020-04-12 21:18:02 回复(1)
累加不同数字出现的次数,次数从0开始加
0+1+2+0+3+0=6
0+0+0+1+2+3=6
0+0+0+0+1+0=1
发表于 2022-06-02 00:05:09 回复(0)
xs[-1]难道不会溢出嘛😐
发表于 2021-05-04 11:52:25 回复(1)
没看懂。。
发表于 2021-04-15 20:05:47 回复(0)

总结下来就是:

for(int i =0; i<n; i++) 
{ 
    ans = xs[i] + ys[i] - pair(x, y); 
}

再考虑,对应value值在自增过程中具体是多少。

编辑于 2021-05-18 21:35:01 回复(0)
这题其实就是考后自增
发表于 2020-11-14 22:01:11 回复(0)
算错了 注意是后++
发表于 2020-03-02 12:30:44 回复(0)

出现的次数

发表于 2020-02-15 08:13:48 回复(0)

这道题的最终输出结果是 11

我们可以把这道题想象成在平面坐标系里“找老乡”。它的本质是计算有多少对点,它们要么在同一条竖线上(横坐标 $x$ 相同),要么在同一条横线上(纵坐标 $y$ 相同)

核心逻辑通俗解释

代码里用到了三个“记事本”(map):

  • xs:记录某个横坐标 $x$ 已经出现了多少次。

  • ys:记录某个纵坐标 $y$ 已经出现了多少次。

  • zs:记录某个具体的位置 $(x, y)$ 已经出现了多少次。

每次输入一个新的点 $(x, y)$ 时,程序会做以下三步思考:

  1. 找同竖线的老乡: 看看之前有几个点的 $x$ 和我现在一样?有几个,就说明我能和它们凑成几对。ans += xs[x]就是把这些对数加到总答案里。

  2. 找同横线的老乡: 看看之前有几个点的 $y$ 和我现在一样?同理,加到总答案里,ans += ys[y]。

  3. 去除重复计算: 如果之前有一个点,既跟我同竖线,又跟我同横线,那它不就是跟我在完全同一个位置的重合点吗?在第一步和第二步里,这个重合点被算了两次!所以我们需要减去一次来修正误差,这就有了ans -= zs[make_pair(x, y)]。

注:代码里的xs[x]++叫“后置递增”,意思是先使用当前本子上的数量来算ans,然后再把本子上的记录加一


逐步拆解计算过程

刚开始,总对数ans = 0,所有的记事本都是空的。我们依次处理输入的 6 个点:

第 1 个点 (0, 0):

  • 之前没见过 $x=0$,没见过 $y=0$,也没见过 $(0, 0)$。

  • 计算:ans+= 0 + 0 - 0。此时ans依然是 0

  • 更新记录:$x=0$ 出现 1 次,$y=0$ 出现 1 次,$(0, 0)$ 出现 1 次。

第 2 个点 (0, 1):

  • 之前见过 1 次 $x=0$。没见过 $y=1$。没见过 $(0, 1)$。

  • 计算:ans+= 1 + 0 - 0 = 1

  • 更新记录:$x=0$ 累计 2 次,$y=1$ 出现 1 次,$(0, 1)$ 出现 1 次。

第 3 个点 (0, 2):

  • 之前见过 2 次 $x=0$。没见过 $y=2$。没见过 $(0, 2)$。

  • 计算:ans+= 2 + 0 - 0 = 3

  • 更新记录:$x=0$ 累计 3 次,$y=2$ 出现 1 次,$(0, 2)$ 出现 1 次。

第 4 个点 (-1, 1):

  • 之前没见过 $x=-1$。但见过 1 次 $y=1$(正是第 2 个点)。没见过 $(-1, 1)$。

  • 计算:ans+= 0 + 1 - 0 = 4

  • 更新记录:$x=-1$ 出现 1 次,$y=1$ 累计 2 次,$(-1, 1)$ 出现 1 次。

第 5 个点 (0, 1) —— 注意,这是个出现过的重复点:

  • 之前见过 3 次 $x=0$。见过 2 次 $y=1$。并且,之前见过 1 次 $(0, 1)$ 本尊!

  • 计算:ans+= 3 + 2 - 1 = 8。(这里的-1就是为了抵消双重计算)。

  • 更新记录:$x=0$ 累计 4 次,$y=1$ 累计 3 次,$(0, 1)$ 累计 2 次。

第 6 个点 (1, 1):

  • 之前没见过 $x=1$。见过 3 次 $y=1$。没见过 $(1, 1)$。

  • 计算:ans+= 0 + 3 - 0 = 11

循环结束,最终打印的结果即为 11


这其实是算法编程中非常经典的**“容斥原理”**(Principle of Inclusion-Exclusion)结合哈希表(Map)的巧妙应用。来自gemeni3.1pro的回答

发表于 2026-03-05 13:29:47 回复(0)
有map就是11
发表于 2022-05-28 15:54:32 回复(0)
这道题手模都可以吧
发表于 2019-08-23 07:14:59 回复(0)