博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
bzoj1925(SCOI2010)地精部落
阅读量:6891 次
发布时间:2019-06-27

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

题目:

要怎样才能想出正解呢?

当然有一维表示从1到 i 。

  发现最后是递增的方案数=最后是递减的方案数,因为其实按值把 j 变成 i - j + 1 就行了。所以记一个递增或递减,ans*=2就行了。

指定新来一个数只能加到末尾,所以第二维记录末尾的数是 j 且是递增或递减;

如果新来的数只能加到末尾,怎么保证求了所有情况?

  需要换个想法:不是前 i 个数,而是前n个数里的 i 个数;不是末尾是 j ,而是末尾是第 j 小的数。

  因为最后会求满n个数,所以前期不用乘什么(比如1324不用乘什么来涵盖2435,因为在一共有n个数的时候,5就会出现在后面了)。

  这样好像就不错了。

怎么推?来自阿当学长的博客:

  发现递增和递减之间有两个关系:如果用f [ ] [ ]表示最后递增,g [ ] [ ] 表示最后递减,则

  f [ i ] [ j ] = ∑(k∈[1,j-1])g [ i-1 ] [ k ];g [ i ] [ j ] = f [ i ] [ i - j + 1 ];

  于是 f [ i ] [ j ] = ∑(k∈[1,j-1]) f [ i - 1 ] [ i - j ];

  即 f [ i ] [ j ] = ∑(k∈[i-1,i-j+1]) f [ i - 1 ] [ k ];

  发现f [ i ] [ j-1 ] = ∑(k∈[i-1,i-j+2]) f [ i - 1 ] [ k ];

  所以f [ i ] [ j ] = f [ i ] [ j - 1 ] + f [ i - 1 ] [ i - j + 1 ];

  真是太美好了。

但是自己怎么才能想出来呢?

  首先第二维按套路应该记一个具体的数。然后发现递增和递减的微妙等价关系,于是设计两个数组表示递增和递减,最后推得美妙式子吗?

  前提是思想灵活一点,就能知道可以指定新来的数加在最后面,进而得出种种状态设计吧。

#include
#include
#include
using namespace std;const int N=4205;int n,p,f[2][N],ans;int main(){ scanf("%d%d",&n,&p); f[0][1]=1;//因为f[1][1]=1 for(int i=1;i<=n;i++) for(int j=1;j<=i;j++) f[i&1][j]=(f[i&1][j-1]+f[(i-1)&1][i-j+1])%p; for(int j=1;j<=n;j++) (ans+=f[n&1][j])%=p; (ans<<=1)%=p; printf("%d",ans); return 0;}

 

转载于:https://www.cnblogs.com/Narh/p/9135070.html

你可能感兴趣的文章
salt 安装脚本
查看>>
获取Spring容器中的Bean
查看>>
ORA-01210: data file header is media corrupt
查看>>
Aerospike开发指南【中文】
查看>>
Python批量修改一个目录文件名
查看>>
rhel6.3 ntp服务器搭建过程
查看>>
Java数组的创建和初始化
查看>>
文档类型定义
查看>>
PHP POST接收处理 IOS上传NSData图片数据,上传图片到服务器
查看>>
Windows2008 R2修改3389端口教程
查看>>
SW2014中文版本出现中文语言丢失时可以安装2011的包修复
查看>>
SOAP接口
查看>>
编译安装
查看>>
IP报文头
查看>>
百度统计个人初探
查看>>
我的友情链接
查看>>
phpstorm使用
查看>>
单元测试、集成测试和系统测试的不同之处[转]
查看>>
Elasticsearch注意事项
查看>>
【数据结构】找出N个数据中最大的前k个数据(利用堆排序)
查看>>