UVALive 5990 Array Diversity (容斥原理)

题目

UVALive 5990 Array Diversity

题意

给一个长度为n的序列,问同时包含最大值和最小值的子串和子序列的个数各是多少

解法

  1. 当序列的最大值和最小值相同时,即序列有同一个数组成,那么

    • 子串的个数为:\(n*(n+1)/2\)
    • 子序列的个数:\(2^n-1\)
  2. 最大值和最小值不同时,

    • 对于子串,用pos1表示最后遇到的最小值的位置,pos2表示最后遇到的最大值的位置,每一个位置i对于ans1的贡献为\(min(pos1, pos2)\)
    • 对于子序列,根据容斥原理,同时包含最大值和最小值的子序列的个数 = 总的子序列的个数 - 不包含最大值的子序列个数 - 不包含最小值的子序列个数 + 既不包含最大值也不包含最小值的子序列的个数,即

    \[ans2=(sum[n]-1)-(sum[n-maxnum]-1)-(sum[n-minnum]-1)+(sum[n-maxnum-minnum]-1) \]

代码

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 100100;
const long long MOD = 1e9 + 7;
const long long INF = 0x3f3f3f3f;
long long a[N], sum[N];
void init() {
    sum[0] = 1;
    for(int i = 1; i < N; i++)
        sum[i] = (sum[i - 1] * 2) % MOD;
}
int main() {
    int T, n;
    init();
    scanf("%d", &T);
    while(T--) {
        scanf("%d", &n);
        long long _max = 0, _min = INF;
        for(int i = 1; i <= n; i++) {
            scanf("%lld", &a[i]);
            _max = max(_max, a[i]);
            _min = min(_min, a[i]);
        }
        if(_max == _min) {
            printf("%lld %lld\n", (n * (n + 1) / 2) % MOD, sum[n] - 1);
            continue;
        }
        int maxnum = 0, minnum = 0;
        long long ans1 = 0, ans2 = 0;
        int pos1 = 0, pos2 = 0;
        for(int i = 1; i <= n; i++) {
            if(a[i] == _max) {
                maxnum ++;
                pos1 = i;
            }
            if(a[i] == _min) {
                minnum ++;
                pos2 = i;
            }
            ans1 = (ans1 + min(pos1, pos2)) % MOD;
        }
        ans2 = ((((sum[n] - 1) - (sum[n - maxnum] - 1) + MOD) % MOD - sum[n - minnum] + MOD) % MOD + sum[n - maxnum - minnum]) % MOD;
        printf("%lld %lld\n", ans1, ans2);
    }
    return 0;
}

Source

Regionals 2011 Asia - Amritapuri

posted @ 2015-08-24 18:13  ACM_Record  阅读(161)  评论(0编辑  收藏  举报