抱歉,您的浏览器无法访问本站

本页面需要浏览器支持(启用)JavaScript


了解详情 >

[原创]ZOJ 3872 Beauty of Array 第 12 届浙江省省赛 D 题 [思维] 【数学】

2016-04-19 00:23:29 Tabris_ 阅读数:530


博客爬取于 2020-06-14 22:44:31
以下为正文

版权声明:本文为 Tabris 原创文章,未经博主允许不得私自转载。
https://blog.csdn.net/qq_33184171/article/details/51184895


题目链接 : http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3872

Beauty of Array


Time Limit: 2 Seconds Memory Limit: 65536 KB


Edward has an array A with N integers. He defines the beauty of an array as the summation of all distinct integers in the array. Now Edward wants to know the summation of the beauty of all contiguous subarray of the array A.

Input
There are multiple test cases. The first line of input contains an integer T indicating the number of test cases. For each test case:

The first line contains an integer N (1 <= N <= 100000), which indicates the size of the array. The next line contains N positive integers separated by spaces. Every integer is no larger than 1000000.

Output
For each case, print the answer in one line.

Sample Input
3
5
1 2 3 4 5
3
2 3 3
4
2 3 3 2

Sample Output
105
21
38


题目大意 :
给出一个 N 大小的数组,寻找一些这个数组的子集的和,
举个例子吧

1 2 3 4 5

1
1 2
1 2 3
1 2 3 4
1 2 3 4 5
_ 2
_ 2 3
_ 2 3 4
_ 2 3 4 5
_ _ 3
_ _ 3 4
_ _ 3 4 5
_ _ _ 4
_ _ _ 4 5
_ _ _ _ 5

举例子的话 很形象了 就不再解释了

计算这些数组的和 (包括最开始输入的几个数)
如果 在每一个子集 中如果有重复出现的数则只加一遍;

数据非常大 10^6 暴力一定会超时

本题的主要思路就是 输入一个数 就把这个数包括之前的数新产生的符合题意的子集的和加入


输入 1 时 1
子集为
1

输入 2 时 1 2
新增子集为
1 2
_ 2
输入 3 时 1 2 3
新增子集为
1 2 3
_ 2 3
_ _ 3
输入 4 时 1 2 3 4
新增子集为
1 2 3 4
_ 2 3 4
_ _ 3 4
_ _ _ 4
输入 5 时 1 2 3 4 5
新增子集为
1 2 3 4 5
_ 2 3 4 5
_ _ 3 4 5
_ _ _ 4 5
_ _ _ _ 5

综合一下就是
1 2 3 4 5
1
1 2
1 2 3
1 2 3 4
1 2 3 4 5
_ 2
_ 2 3
_ 2 3 4
_ 2 3 4 5
_ _ 3
_ _ 3 4
_ _ 3 4 5
_ _ _ 4
_ _ _ 4 5
_ _ _ _ 5

以上是没有出现重复的情况
每次新增子集为前一种情况的每个新增子集加入这个元素
用一个数存上这些数的和即可

出现重复情况其实也很好理解

假定此时已经输入 1 2 3 4
在输入 3 时
新增子集为
1 2 3 4 3
_ 2 3 4 3
_ _ 3 4 3
_ _ _ 4 3
_ _ _ _ 3
因为之前已经出现过 3 所以新加入的子集中 3 就不需要再重复的加了;
而怎么判断子集中有没有与新输入元素重复的元素呢

观察
1 2 3 4 3
_ 2 3 4 3
_ _ 3 4 3
_ _ _ 4 3
_ _ _ _ 3

不难发现前三个新增子集已经有过 3
但是后两个子集并没有 3
其实想一想,如果输入顺序为 1 3 2 4 3 的话
新增子集为
1 3 2 4 3
_ 3 2 4 3
_ _ 2 4 3
_ _ _ 4 3
_ _ _ _ 3

这时前 2 个新增子集有过 3
后 3 个子集并没有 3
如果在换个顺序 又会发生变化 ;
而我们计算的时候把新增子集的和记录下来
之后再把多加的数值减去就行
不难发现只要与新加入元素相同的元素 在第几次输入 就会有几个子集存在元素重复
这是用一个数组吧这个数存在的位置记录一下就行

但是如果有多个重复的情况呢;
即输入为 3 2 3 4 3
这时新增子集为
3 2 3 4 3
_ 2 3 4 3
_ _ 3 4 3
_ _ _ 4 3
_ _ _ _ 3

发现重复总是以除新输入元素之外最后输入的相同元素判断的;
所以每次更新一下元素出现位置即可;

用 sum 来存储总共的和
用 ans 来存储新增子集的和
这是如果出现相同时
ans- = 输入元素 * 未更新的位置;
就是新增元素的和

综上所述
本题的思路就完全出来了
看似本文叙述非常多,其实都是思维的过程,实际操作起来非常快的。

附本题代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# include <iostream>
# include <stdio.h>
# include <string.h>
using namespace std;
int bb[1000005];
int main()
{
int t,n,x;
scanf("%d",&t);
while(t--)
{
memset(bb,0,sizeof(bb));
scanf("%d",&n);
long long int sum=0,ans=0;
for(long long int i=1; i<=n; i++)
{
scanf("%d",&x);
ans+=(i*x);
sum+=ans;
sum-=bb[x]*x;
ans-=bb[x]*x;
bb[x]=i;
}
printf("%lld\n",sum);
}
return 0;
}

评论