[原创]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;
}