【问题描述】

小美今天对于数列很有兴趣。小美打算找出一些漂亮的序列。一个漂亮的序列的限制如下:

  1. 长度为 n ,而且数列里只包含 [1,n] 的整数。
  2. 要不是不降的序列就是不升的序列。

小美想知道有多少个合法的序列满足要求。

【输入格式】

从文件 pretty.in 中读入数据。

第一行一个正整数 n 表示数列的大小。

【输出格式】

输出到文件 pretty.out 中。

第一行输出一个数字表示答案。由于这个数字会很大,你需要输出他

模 1000000007 。

【样例】

【样例输入】

2

【样例输出】

4

【样例输入】

3

【样例输出】

17

【题目来源】

CF 57C

题解

首先,看到这样的问题,我们想到这应该是道dp。

我们设\(f[i][j]\)表示前\(i\)个数到达最后一位是\(j\)的递增序列的方案数,则不难根据对称性得出答案为\(2\sum_{i=1}^{n}f[n][i]-n\),减\(i\)是为了减去递增和递减都包含的情况(即全部相同的请况,那显然是\(i\))。

我们发现\(f[i][j]\)的状态由所有\(f[i-1][k](k\le j)\)的状态在结尾加上\(k\)转移过来。故转移方程为:\(f[i][j] = \sum_{k=1}^{j}f[i-1][k]\)。

于是暴力程序就打出来了,那么让我们打张表:

#include <cstdio>

const int n = 10;

int f[n+1][n+1];

int main()
{
freopen("biao.out", "w", stdout);
int ans;
for(int i = 1; i <= n; ++i)
f[1][i] = 1;
for(int i = 2; i <= n; ++i)
{
ans = 0;
for(int j = 1; j <= n; ++j)
for(int k = 1; k <= j; ++k)
f[i][j] = f[i][j] + f[i-1][k];
for(int j = 1; j <= i; ++j)
ans = ans+f[i][j];
}
for(int i = 1; i <= n; ++i)
{
for(int j = 1; j <= n; ++j)
printf("%5d ", f[i][j]);
puts("");
}
}

biao.out

    1     1     1     1     1     1     1     1     1     1
1 2 3 4 5 6 7 8 9 10
1 3 6 10 15 21 28 36 45 55
1 4 10 20 35 56 84 120 165 220
1 5 15 35 70 126 210 330 495 715
1 6 21 56 126 252 462 792 1287 2002
1 7 28 84 210 462 924 1716 3003 5005
1 8 36 120 330 792 1716 3432 6435 11440
1 9 45 165 495 1287 3003 6435 12870 24310
1 10 55 220 715 2002 5005 11440 24310 48620

一看发现:这不是杨辉三角吗?

于是毫不犹豫地打了个\(n^2\),然后就T飞了。

竟然没想到\(\sum_{i=1}^{n}f[n][i] = f[n+1][n] = C^{n}_{2n}\)(可以直接推,也可以看作是在序列结尾加一个\(n\)进行限制)。

于是答案就变成了\(2C^n_{2n}-n\)。取模要求逆元,用费马小定理做一下,总时间复杂度为\(O(n)\)。

当然,杨辉三角也是可以直接推出来的:

\[f[i][j] = \sum_{k=1}^{j}f[i-1][k] = f[i-1][j] + \sum_{k=1}^{j-1}f[i-1][k] = f[i-1][j] + f[i-1][j-1].
\]

以下是我的代码(由于模拟赛加了文件读入输出):

#include <fstream>

using namespace std;

typedef long long LL;

ifstream fin("pretty.in");
ofstream fout("pretty.out"); inline LL pow(LL x, LL y, LL mod)
{
LL ans = 1;
for(; y; y >>= 1, x = (x*x)%mod)
if(y & 1)
ans = (ans*x) % mod;
return ans % mod;
} const LL mod = 1000000007;
const int maxn = 100005; LL fac[maxn<<1]; int main()
{
LL n;
fin >> n;
fac[0] = 1;
for(int i = 1; i <= (n<<1); ++i)
fac[i] = fac[i-1] * i % mod;
fout << (fac[n<<1]* pow(fac[n]*fac[n]%mod, mod-2, mod)) % mod - n << endl;
return 0;
}

最新文章

  1. 一步步学习javascript基础篇(0):开篇索引
  2. 服务器重启后导致访问ArcServer地图服务须登录
  3. php判断是否为微信浏览器访问
  4. Framework manager编写SQL错误整理
  5. IOS基础之 (十二) Block
  6. Share SDK 第三方登录
  7. 【Android学习】调用系统相机
  8. mysql5.7下载与安装,php5.6与mysql5.7整合
  9. POJ 3414 Pots ( BFS , 打印路径 )
  10. 实现跨线程访问UI控件的3种方法
  11. 让你不再纠结GitHub:Git起步
  12. Java主线程等待子线程、线程池
  13. Asp.Net Identity 2.0 认证
  14. JavaScript实现360度全景图片展示效果
  15. 设计模式一:关于C++写观察者模式的一些收获
  16. CNN 文本分类
  17. [UWP]使用Picker实现一个简单的ColorPicker弹窗
  18. python 小程序,输错三次密码锁定账户
  19. JDBC---Mysql(1)
  20. Ubuntu Server16.04 配置网卡

热门文章

  1. Shell脚本之五 基本运算符
  2. Alpha冲刺(7/10)——2019.4.29
  3. JMeter工具学习(二)——获取登录 token
  4. jmeter 获取总的线程数
  5. 责任链(ChainOfResponsibility)模式
  6. idea 全局内容搜索和替换
  7. Laravel学习记录
  8. 59 网络编程(一)——端口与InetSocketAddress
  9. Java学习:final关键字的使用与注意事项
  10. NVDLA软件架构和源码解析 第一章—内核驱动【华为云技术分享】