博客
关于我
Random IS
阅读量:306 次
发布时间:2019-03-04

本文共 2625 字,大约阅读时间需要 8 分钟。

题目

据说是 ATCODER 的题。

题目描述

沐目女未 喜欢进步。她的名言:“又来了两个人,我又要 r n k    − = 2 {\tt rnk}\;-=2 rnk=2 了!”

今天她又要进步。她要瞎选一些元素,但是要保证构成的子序列单调上升。什么糟糕要求啊喂。

具体来说,对于所有可加入的元素,她会等概率的选择一个并加入。“可加入” 指,加入这个元素之后,子序列仍然是单增的。如果没有可加入的元素,她就会眼泪汪汪的结束选择。

你能告诉可爱的 沐目女未 最终选出的元素的期望数量吗?

数据范围与提示

n ≤ 2 × 1 0 3 n\le 2\times 10^3 n2×103 a i ≤ n a_i\le n ain a i ≠ a j ( i ≠ j ) a_i\ne a_j(i\ne j) ai=aj(i=j)

思路

区间 d p \tt dp dp 的思路比较显然。

f ( l , r ) f(l,r) f(l,r) 表示 ( l , r ) (l,r) (l,r) 之间继续选择,已经选择了 a l a_l al a r a_r ar 。那么有转移方程

f ( l , r ) = 1 + ∑ l < k < r a l < a k < a r f ( l , k ) + f ( k , r ) ∣ S ∣ f(l,r)=1+\sum_{l<k<r}^{a_l<a_k<a_r}\frac{f(l,k)+f(k,r)}{|S|} f(l,r)=1+l<k<ral<ak<arSf(l,k)+f(k,r)

想个办法优化。这里就要给区间 d p \tt dp dp 只会枚举长度与左端点的人(包括我自己)提个醒了:区间 d p \tt dp dp 还有一种枚举方式是 左端点从大到小、右端点从小到大

如果是这种枚举方式,可以用树状数组优化。因为就是求 a l < a k < a r a_l<a_k<a_r al<ak<ar k k k 的所有 f ( l , k ) f(l,k) f(l,k) 的和。至于 f ( k , r ) f(k,r) f(k,r) ,可以对于每个 r r r 都开一个树状数组 😉

于是 O ( n 2 log ⁡ n ) \mathcal O(n^2\log n) O(n2logn) 解决了。话说不会被卡常咩。

代码

#include 
#include
#include
#include
#include
using namespace std;typedef long long int_;inline int readint(){ int a = 0; char c = getchar(), f = 1; for(; c<'0'||c>'9'; c=getchar()) if(c == '-') f = -f; for(; '0'<=c&&c<='9'; c=getchar()) a = (a<<3)+(a<<1)+(c^48); return a*f;}template < typename T >inline void getMax(T &a,const T &b){ (a < b) ? (a = b) : 0;}template < typename T >inline void getMin(T &a,const T &b){ (b < a) ? (a = b) : 0;}const int MaxN = 2010;const int Mod = 1e9+7;int a[MaxN], dp[MaxN][MaxN], n;struct BIT{ int c[MaxN]; void clear(){ for(int i=1; i<=n; ++i) c[i] = 0; } void modify(int id,int v){ for(int i=id; i<=n; i+=(i&-i)) c[i] = (c[i]+v)%Mod; } int query(int id){ if(id > n) id = n; int res = 0; for(int i=id; i; i-=(i&-i)) res = (res+c[i])%Mod; return res; }};BIT r[MaxN]; // 每个右端点都开一个BIT cnt, l; // cnt是个数 l是当前左端点int_ inv[MaxN]; // 逆元int main(){ n = readint(); for(int i=1; i<=n; ++i) a[i] = readint(); inv[1] = 1; // 预处理逆元 for(int i=2; i<=n; ++i) inv[i] = (Mod-Mod/i) * inv[Mod%i]%Mod; a[n+1] = n+1; // 末尾的虚点 for(int i=n-1; i>=0; --i){ l.clear(), cnt.clear(); for(int j=i+2; j<=n+1; ++j){ r[j].modify(a[i+1],dp[i+1][j]); l.modify(a[j-1],dp[i][j-1]); cnt.modify(a[j-1],1); int s = cnt.query(a[j]) - cnt.query(a[i]); if(s <= 0) continue; int all = l.query(a[j]) - l.query(a[i]) + r[j].query(a[j]) - r[j].query(a[i]); all = (all%Mod+Mod)%Mod; dp[i][j] = (all*inv[s]+1)%Mod;// printf("dp[%d,%d] = %d\n",i,j,dp[i][j]); } } printf("%d\n",dp[0][n+1]); return 0;}

转载地址:http://lntq.baihongyu.com/

你可能感兴趣的文章
shell 中的 set命令 -e -o 选项作用
查看>>
Python中JSON的基本使用
查看>>
函数的默认参数值,即在定义参数的时候给它一个默认值
查看>>
ubuntu install baidu inputmethod
查看>>
程序员建议(忘记从哪里转的了,反正是csdn上的一个兄弟)
查看>>
电脑重装系统后提示invalid partition table怎么解决
查看>>
c++ primer 5th 练习11.9自己编写的答案
查看>>
web实现断点续传
查看>>
自定义BootstrapTable扩展:分页跳转到指定页码
查看>>
Python3逻辑运算符
查看>>
【学习笔记】欧拉函数,欧拉公式
查看>>
Python3序列
查看>>
React中设置404页面
查看>>
BootstrapValidator手动触发部分验证
查看>>
vue调试工具vue-devtools安装及使用
查看>>
CSS总结div中的内容垂直居中的四种方法
查看>>
[BZOJ4878]挑战NP-Hard
查看>>
vue指令之v-for
查看>>
[CF1278F]Cards
查看>>
jQuery实现无刷新切换主题皮肤功能
查看>>