UVALive 5990 Array Diversit

题意:对于一个数列A,substring是一个连续子串,subsequence是其非连续子序列。对于一个数字序列,记它的diversity是它的最大元素减去最小元素的差。给出一个数字序列,求与它diversity相同的substring和subsequence各有多少个。比如若A为1,4,3,4,则答案为3和6。

解法:组合数学问题。首先,记A中最大元素为ma,最小元素为mi,且最大元素有s1个,最小元素有s2个,数列A长度为n。

   则A的所有subsequence共有2^n个,不含ma的subsequence有2^(n-s1)个,不含mi的subsequence有2^(n-s2)个,mi和ma都不含的有2^(n-s1-s2)个,由容斥原理,所求为2^n - 2^(n-s1) - 2^(n-s2) + 2^(n-s1-s2)个。

   对于substring的个数,选取的的substring为A[begin] 到 A[end],枚举end从0到n-1,并且用t1记录目前位置最后出现的mi的位置,t2记录目前最后出现的ma的位置,则对于每个枚举的end,ans += min(t1, t2)。详见代码。

比赛的时候没有想清楚,substring个数的求法写得好复杂。。。后来看了男神代码自己默默模仿了一份。。。。

tag:组合数学,counting

 1 /*
 2  * Author:  Plumrain
 3  * Created Time:  2013-12-03 19:43
 4  * File Name: math-LA-5990.cpp
 5  */
 6 #include <iostream>
 7 #include <cstdio>
 8 #include <algorithm>
 9 
10 using namespace std;
11 
12 typedef long long int64;
13 const int64 mod = 1000000007;
14 const int N = 100005;
15 
16 int64 g[N], a[N];
17 int64 min(int64 a, int64 b) {return a > b ? b : a;}
18 int64 max(int64 a, int64 b) {return a > b ? a : b;}
19 
20 int main()
21 {
22     g[0] = 1;
23     for (int i = 1; i < N; ++ i)
24         g[i] = g[i-1] * 2 % mod;
25     
26     int T, n;
27     scanf ("%d", &T);
28     while (T--){
29         int64 mi = mod, ma = 1;
30         scanf ("%d", &n);
31         for (int i = 0; i < n; ++ i){
32             scanf ("%lld", &a[i]);
33             mi = min(mi, a[i]);
34             ma = max(ma, a[i]);
35         }
36 
37         int64 ans1 = 0, ans2 = 0;
38 
39         if (mi == ma){
40             ans1 = ((int64)(n + 1) * n / 2) % mod;
41             ans2 = g[n] - 1;
42             printf ("%lld %lld\n", ans1, ans2);
43             continue;
44         }
45 
46         int t1 = -1, t2 = -1, s1 = 0, s2 = 0;
47         for (int i = 0; i < n; ++ i){
48             if (a[i] == mi){
49                 ++ s1; t1 = i;
50             }
51             if (a[i] == ma){
52                 ++ s2; t2 = i;
53             }
54 
55             ans1 = (ans1 + min(t1+1, t2+1)) % mod;
56         }
57 
58         ans2 = (g[n] - g[n-s1] - g[n-s2] + g[n-s1-s2]) % mod;
59         if (ans2 < 0) ans2 += mod;
60         printf ("%lld %lld\n", ans1, ans2);
61     }
62     return 0;
63 }
View Code

 

 

posted @ 2013-12-03 20:25  Plumrain  阅读(346)  评论(0编辑  收藏  举报