链接
题目描述
给出一个长度为n的排列ai以及seed,求
结果对1000000007取模
mid(l,r)指al,al+1,…,ar-1,ar 的中位数
样例输入
4 1
1 2 3 4
样例输出
50
思路
每次固定右端点,然后枚举左端点,用链表存下,再转移中位数就好了
代码
#include <iostream>
#include <cstdio>
#include <cmath>
#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], sn, seed, ans, n;
int ksm(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]);
sn = ksm(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 + 1;
for(int i = n; i >= 1; --i) {
int posA = pos1, posB = pos2;
T = S;
int now = ksm(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 * sn % 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;
}