BZOJ 4361 ISN
题面
题目描述
给出一个长度为n的序列A(A1,A2...AN)。如果序列A不是非降的,你必须从中删去一个数,
这一操作,直到A非降为止。求有多少种不同的操作方案,答案模10^9+7。
输入格式
第一行一个整数n。
接下来一行n个整数,描述A。
输出格式
一行一个整数,描述答案。
样例输入
4
1 7 5 3
样例输出
18
数据范围
1<=N<=2000
ai没超long long就对了
关于题意
非降 = 单调不下降
题解
我们考虑一个长度为\(i\)的串, 必定是由一个长度为\(i + 1\)的串去掉一位而来, 并且满足这个长度为\(i + 1\)的串是不合法的.
因此我们令\(g[i]\)表示原串中长度为\(i\)的不下降子序列的数量, 则结束时串的长度为\(i\)的方案数为\(f[i] = g[i] \times (n - i)! - g[i + 1] \times (n - i - 1)! \times (i + 1)\), 用一棵权值树状数组来进行优化, \(O(n^2 \log n)\)即可.
代码:
#include <cstdio>
#include <cctype>
#include <algorithm>
#include <cstring>
namespace Zeonfai
{
inline int getInt()
{
int a = 0, sgn = 1;
char c;
while(! isdigit(c = getchar())) if(c == '-') sgn *= -1;
while(isdigit(c)) a = a * 10 + c - '0', c = getchar();
return a * sgn;
}
}
const int MOD = (int)1e9 + 7, N = 2000;
int n;
struct record
{
int val, pos;
inline int friend operator <(record a, record b)
{
return a.val < b.val;
}
}rec[N + 1];
struct binaryIndexedTree
{
int a[N + 1];
inline void clear()
{
memset(a, 0, sizeof(a));
}
inline void modify(int pos, int dlt)
{
for(int i = pos; i <= n; i += i & - i) a[i] = (a[i] + dlt) % MOD;
}
inline int query(int pos)
{
int res = 0;
for(int i = pos; i; i -= i & - i) res = (res + a[i]) % MOD;
return res;
}
}BIT;
int main()
{
#ifndef ONLINE_JUDGE
freopen("ISN.in", "r", stdin);
freopen("ISN.out", "w", stdout);
#endif
using namespace Zeonfai;
n = getInt();
for(int i = 1; i <= n; ++ i) rec[i].val = getInt(), rec[i].pos = i;
std::sort(rec + 1, rec + n + 1);
static int a[N + 1];
int p = 1; a[rec[1].pos] = p;
for(int i = 2; i <= n; ++ i) a[rec[i].pos] = rec[i].val == rec[i - 1].val ? p : ++ p;
static int g[N + 1], h[N + 1];
g[1] = n % MOD; for(int i = 1; i <= n; ++ i) h[i] = 1;
for(int i = 2; i <= n; ++ i)
{
g[i] = 0; BIT.clear();
for(int j = 1; j <= n; ++ j)
{
int tmp = BIT.query(a[j]);
BIT.modify(a[j], h[j]);
h[j] = tmp;
g[i] = (g[i] + h[j]) % MOD;
}
}
static int frac[N + 1]; frac[0] = 1;
for(int i = 1; i <= n; ++ i) frac[i] = (long long)frac[i - 1] * i % MOD;
static int f[N + 1];
for(int i = 1; i <= n; ++ i) f[i] = ((long long)g[i] * frac[n - i] % MOD - (i == n ? 0 : (long long)g[i + 1] * frac[n - i - 1] % MOD * (i + 1) % MOD) + MOD) % MOD;
int ans = 0;
for(int i = 1; i <= n; ++ i) ans = (ans + f[i]) % MOD;
printf("%d\n", ans);
}