题意:给定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; }