版权声明:欢迎借鉴,谢绝抄搬。 https://blog.csdn.net/Gx_Man_VIP/article/details/88542090
题目大意:
给出一个长度为n的全排列
,
设
为全排列中区间
的中位数,
求
。
答案对
取模。
分析:
提前处理出
,设为
枚举右端点
,
为排列
中某个位置
对
建立链表S,不是
,是数
,
可以由
删掉数
令
=
然后从左到右的枚举左端点
,
每次用链表维护一下中位数就可以,因为可以数列长度为偶数,那么我们令
表示2个中位数分别的位置,如果数列长度为奇数,则
。
每次
都将
中的
删掉,
可以通过
的预处理在每次
时O(1)计算,每次维护链表都是
的
然后这题就搞完了
时间复杂度是
代码:
#include <iostream>
#include <cstdio>
#include <cmath>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <cstring>
#include <algorithm>
#define N 10005
using namespace std;
typedef long long ll;
const int mo = 1e9 + 7;
struct Node {
int pre[N], nxt[N];
void del(int x)
{
nxt[pre[x]] = nxt[x];
pre[nxt[x]] = pre[x];
}
}S, T;
int p[N], seednum, seed, ans, n;
int power(int x, int y)
{
int rp = 1;
for (; y; y >>= 1)
{
if (y & 1) rp = (ll)rp * x % mo;
x = (ll)x * x % mo;
}
return rp;
}
int main()
{
scanf("%d %d", &n, &seed);
for (int i = 1; i <= n; i++) scanf("%d", &p[i]);
seednum = power(seed, n);
for(int i = 1; i <= n + 1; i++) S.pre[i] = i - 1, S.nxt[i - 1] = i;
int pos1 = (n + 1) / 2, pos2 = (n + 2) / 2;
for (int i = n; i >= 1; i--)
{
int posA = pos1, posB = pos2;
T = S;
int now = power(seed, i);
for (int j = 1; j <= i; j++)
{
ans = (ans + (ll)now * (posA + posB) % mo) % mo;
if (posA == posB)
{
if (p[j] <= posB) posB = T.nxt[posB];
if (p[j] >= posA) posA = T.pre[posA];
}
else
{
if (p[j] <= posA) posA = T.nxt[posA];
if (p[j] >= posB) posB = T.pre[posB];
}
T.del(p[j]);
now = (ll)now * seednum % mo;
}
if (pos1 == pos2)
{
if (p[i] <= pos2) pos2 = S.nxt[pos2];
if (p[i] >= pos1) pos1 = S.pre[pos1];
}
else
{
if (p[i] <= pos1) pos1 = S.nxt[pos1];
if (p[i] >= pos2) pos2 = S.pre[pos2];
}
S.del(p[i]);
}
printf("%d\n", ans);
return 0;
}