您的位置:首页 > 产品设计 > UI/UE

【ZOJ3929 The 16th Zhejiang University Programming ContestC】【DP】Deque and Balls n个数放入双端队列2^n种方案有多少个位置

2016-04-12 13:07 537 查看
Deque and Balls
Time Limit: 2 Seconds      Memory Limit: 65536 KB

There are n balls, where the i-th ball is labeled as pi. You are going to put n balls into a deque. In the i-th
turn, you need to put the i-th ball to the deque. Each ball will be put to both ends of the deque with equal probability.

Let the sequence (x1, x2, ..., xn) be the labels of the balls in the deque from left to right. The beauty of the deque B(x1, x2,
..., xn) is defined as the number of descents in the sequence. For the sequence (x1, x2, ..., xn), a descent is a position i (1
≤ i < n) with xi > xi+1.

You need to find the expected value of B(x1, x2, ..., xn).

Deque is a double-ended queue for which elements can be added to or removed from either the front (head) or the back (tail).

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 (2 ≤ n ≤ 100000) -- the number of balls. The second line contains n integers: p1, p2,
..., pn (1 ≤ pi ≤ n).

Output

For each test case, if the expected value is E, you should output E⋅2n mod (109 + 7).

Sample Input

2
2
1 2
3
2 2 2

Sample Output

2
0


#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<ctype.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); }
#define MS(x,y) memset(x,y,sizeof(x))
#define MC(x,y) memcpy(x,y,sizeof(x))
#define MP(x,y) make_pair(x,y)
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b>a)a = b; }
template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b<a)a = b; }
const int N = 1e5+10, M = 0, Z = 1e9 + 7, ms63 = 0x3f3f3f3f;
int casenum, casei;
int n, x;
int b
;
int lft
, rgt
;
void add(int &x, int y)
{
x += y;
if (x >= Z)x -= Z;
}
void modify(int a[], int x, int val)
{
for (; x <= n; x += x&-x)add(a[x], val);
}
int check(int a[], int x)
{
int ret = 0;
for (; x; x -= x&-x)add(ret, a[x]);
return ret;
}
int main()
{
b[0] = 1;for (int i = 1; i <= 1e5; ++i)b[i] = b[i - 1] * 2 % Z;
scanf("%d", &casenum);
for (casei = 1; casei <= casenum; ++casei)
{
scanf("%d", &n);
for (int i = 1; i <= n; ++i)lft[i] = rgt[i] = 0;
scanf("%d", &x);
modify(lft, x, 2);
modify(rgt, x, 2);
int ans = 0;
for (int i = 2; i <= n; ++i)
{
scanf("%d", &x);
ans = ans * 2 % Z;
add(ans, check(lft, x - 1));
add(ans, (Z + check(rgt, n) - check(rgt, x)) % Z);
modify(lft, x, b[i-1]);
modify(rgt, x, b[i-1]);
}
printf("%d\n", ans);
}
return 0;
}
/*
【题意】
有n(1e5)个数。
每个数都有一个权值(1~n)
我们有一个双端队列,每个数加入到双端队列的时候,可以加在该队列的前部或者尾部。
这样我们最后一共可以生成2^n个队列。

我们对于这2^n个队列,都扫描一遍。
如果存在一个队列的一个位置i∈[1,n),满足a[i]>a[i+1],那么我们答案的贡献就+1
问你最后的答案是多少(mod (1e9+7))

【类型】
DP 树状数组

【分析】
这题我们可以DP来做。如何做呢?
我们用lft[i]表示数值为i的数出现在整个数列左侧的方案数
用rgt[i]表示数值为i的数出现在整个数列右侧的方案数

那么,当新的一个数加进来时——
1,之前的所有答案都要*2,因为队列的可能性种数*2了,所以之前的答案也要*2
2,对于之前的每个lft[i],它依然继续是lft的条件是当前的数放在了右侧,
这样的话,对于当步决策,使得之前lft[]变化的延展系数为1,所以lft[i]保留不变
3,对于之前的每个rgt[i],它依然继续是rgt的条件是当前的数放在了左侧,
这样的话,对于当步决策,使得之前rgt[]变化的延展系数为1,所以rgt[i]保留不变

于是,在ans*=2后,当步数新放置后,对答案的贡献是lft[1~x-1]+rgt[x+1~n]
这样我们就可以AC啦。

【时间复杂度&&优化】
O()

【数据】
input
3
1 2 3
output

detail
1 2
2 1
1 2 3
2 1 3
3 1 2
3 2 1

*/

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐