SPOJ

题意:给定n个数,求包含最大值和最小值的子集(数字连续)和子序列(数字不连续)的个数。

分析:

1、如果n个数都相同,则子集个数为N * (N + 1) / 2,子序列个数为2N-1。

2、将序列从头到尾扫一遍,每当找到一个最大值和最小值的位置maxid,minid,就以这两个位置的区间为基准,计算集合数。

例如:3 1 4 3 1

当i=2时,此时maxid=2,minid=1,因此由最大值和最小值---1和4能形成两个子集:3 1 4 和 1 4,即min(minid + 1, maxid + 1)个

当i=3时,此时maxid=2,minid=1,因此由最大值和最小值---1和4继续扩展,又能形成两个子集:3 1 4 3 和 1 4 3,

当i=4时,此时maxid=2,minid=4,因此由新的最大值和最小值---1和4继续扩展,又能形成三个子集:3 1 4 3 1 ,1 4 3 1,4 3 1。

3、记录序列中最大值和最小值的个数,分别为maxnum,minnum。

子序列个数为,只由最小值形成的集合数a*只由最大值形成的集合数b*不是最小值和最大值的数形成的集合数c

因为子序列中必须有最大值和最小值,因此a和b不能为空集,所以a=2minnum-1,b=2maxnum-1。

而c可以为空集,所以c=2n-minnum-maxnum

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<cmath>
#include<iostream>
#include<sstream>
#include<iterator>
#include<algorithm>
#include<string>
#include<vector>
#include<set>
#include<map>
#include<stack>
#include<deque>
#include<queue>
#include<list>
#define lowbit(x) (x & (-x))
const double eps = 1e-9;
inline int dcmp(double a, double b){
    if(fabs(a - b) < eps) return 0;
    return a > b ? 1 : -1;
}
typedef long long LL;
typedef unsigned long long ULL;
const int INT_INF = 0x3f3f3f3f;
const int INT_M_INF = 0x7f7f7f7f;
const LL LL_INF = 0x3f3f3f3f3f3f3f3f;
const LL LL_M_INF = 0x7f7f7f7f7f7f7f7f;
const int dr[] = {0, 0, -1, 1, -1, -1, 1, 1};
const int dc[] = {-1, 1, 0, 0, -1, 1, -1, 1};
const LL MOD = 1000000007;
const double pi = acos(-1.0);
const int MAXN = 100000 + 10;
const int MAXT = 1000 + 10;
using namespace std;
LL a[MAXN];
LL POW[MAXN];
void init(){
    POW[0] = 1;
    for(int i = 1; i < MAXN; ++i){
        POW[i] = (POW[i - 1] * 2) % MOD;
    }
}
int main(){
    init();
    int T;
    scanf("%d", &T);
    while(T--){
        int N;
        scanf("%d", &N);
        LL _min = LL_INF;
        LL _max = 0;
        for(int i = 0; i < N; ++i){
            scanf("%lld", &a[i]);
            _max = max(_max, a[i]);
            _min = min(_min, a[i]);
        }
        if(_max == _min){
            LL sum1 = N * (N + 1) / 2;
            LL sum2 = POW[N] - 1;
            printf("%lld %lld
", sum1, sum2);
            continue;
        }
        int maxnum = 0;
        int minnum = 0;
        int minid = -1, maxid = -1;
        LL sum1 = 0;
        for(int i = 0; i < N; ++i){
            if(a[i] == _min){
                minid = i;
                ++minnum;
            }
            if(a[i] == _max){
                maxid = i;
                ++maxnum;
            }
            (sum1 += min(minid + 1, maxid + 1)) %= MOD;
        }
        LL sum2 = ((((POW[minnum] - 1) * (POW[maxnum] - 1)) % MOD) * (POW[N - minnum - maxnum])) % MOD;
        printf("%lld %lld
", sum1, sum2);
    }
    return 0;
}

  

原文地址:https://www.cnblogs.com/tyty-Somnuspoppy/p/7246290.html