Codeforces Good Bye 2015 D. New Year and Ancient Prophecy DP
2015-12-31 15:32
423 查看
题意:把给出的序列分成严格递增的子序列。
思路:dp(ij)=∑j−1k=1dp(i−j,k)+dp(i−j,j)dp_{(ij)}=\sum_{k=1}^{j-1}dp_{(i-j,k)}+dp_{(i-j,j)},其中dp(i,j)dp_{(i,j)}代表第ii个字符结尾,最后一个块的大小为jj。dp(i,j)dp_{(i,j)}只能由dp(i−j,k)dp_{(i-j,k)}得到。其中∑j−1k=1dp(i−j,k)\sum_{k=1}^{j-1}dp_{(i-j,k)}是不用判断的,而dp(i−j,j)dp_{(i-j,j)}是需要判断,因为题目要求的是严格递增的,所以要判断dp(i,j)dp_{(i,j)}能否由dp(i−j,j)dp_{(i-j,j)}得到。这个判断过程我在打CF的时候并不知道,看了别人的代码才学到的,cnt(i,j)cnt_{(i,j)}代表以aia_i和aja_j开头的字符串有多少个字符时相同的。if(ai==aj)cnt(i,j)=cnt(i−1,j−1)+1if(a_i==a_j)cnt_{(i,j)}=cnt_{(i-1,j-1)}+1。然后判断dp(i,j)dp_{(i,j)}能否由dp(i−j,j)dp_{(i-j,j)}得到的时候就可以直接判断不相同的那一位而不用判断整个字符串。
复杂度O(N2)O(N^2)
http://codeforces.com/contest/611/problem/D/********************************************* Problem : Codeforces Good Bye 2015 Author : NMfloat InkTime (c) NM . All Rights Reserved . ********************************************/ #include <map> #include <set> #include <queue> #include <stack> #include <cmath> #include <ctime> #include <cstdio> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> #define rep(i,a,b) for(int i = (a) ; i <= (b) ; i ++) #define rrep(i,a,b) for(int i = (b) ; i >= (a) ; i --) #define repE(p,u) for(Edge * p = G[u].first ; p ; p = p -> next) #define cls(a,x) memset(a,x,sizeof(a)) #define eps 1e-8 using namespace std; const int MOD = 1e9+7; const int INF = 0x3f3f3f3f; const int MAXN = 1e5+5; const int MAXE = 2e5+5; typedef long long LL; typedef unsigned long long ULL; int T,n,m,k; int fx[] = {0,1,-1,0,0}; int fy[] = {0,0,0,-1,1}; char a[5005]; int cnt[5005][5005]; int dp[5005][5005]; int sum[5005][5005]; void input() { } void solve() { cls(cnt,0); rrep(i,1,n) { rrep(j,i+1,n) { if(a[i] == a[j]) { cnt[i][j] = cnt[i+1][j+1] + 1; //代表以i和j开头的两个字符串后面有cnt[i][j]个字符是相等的 } } } //dp[i][j]代表第i为结尾有j个连续字符的有多少个 cls(dp,0); cls(sum,0); dp[0][0] = 1; rep(i,0,n) sum[0][i] = 1; rep(i,1,n) { rep(j,1,i) {//长度 if(a[i-j+1] == '0') continue; dp[i][j] = (dp[i][j] + sum[i-j][j-1]) % MOD; int l = i - 2 * j + 1; int r = i - j + 1; if(l < 1) continue; if(cnt[l][r] < j && a[l+cnt[l][r]] < a[r+cnt[l][r]]) { dp[i][j] = (dp[i][j] + dp[i-j][j])%MOD; } } rep(j,1,n) { sum[i][j] = (dp[i][j] + sum[i][j-1]) % MOD; // printf("%d ",dp[i][j]); } //puts(""); } int ans = 0; rep(i,1,n) { ans = (ans + dp [i]) % MOD; } printf("%d\n",ans); } int main(void) { //freopen("a.in","r",stdin); while(~scanf("%d %s",&n,&a[1])) { input(); solve(); } return 0; }
相关文章推荐
- [Linux] 查看jar包内容
- linux-mysql-store-result
- linux iptables理论学习
- Centos 7中部署LAMP
- Linux的关机与重启命令
- Consul实践之Consul结合nginx构建高可用可扩展的Web服务
- CentOS6.7部署MySQL多实例
- linux mysql 5.5升级到5.6 使用MySQL的APT库
- Linux下Appium环境搭建
- shell数组建立和基本使用方法
- jenkins+ant+jmeter(linux)
- Linux 下类似画图工具
- linux sqlite3 数据库查看工具
- openssl移植
- Yii 2.0 在Nginx下的urlManager配置
- CAS--使用 CAS 在 Tomcat 中实现单点登录
- linux安装jdk,mysql,tomcat
- 在Windows下用Virtualbox虚拟linux时共享文件夹设置的方法
- Centos boost1.55 安装
- linux6.5安装11.2.0.4rac,在安装GI跑脚本</u01/app/11.2.0/grid/root.sh>出现CRS-4046 CRS-4000 错误