lcp+dp Codeforces611D New Year and Ancient Prophecy
来源:互联网 发布:福州几个打车软件 编辑:程序博客网 时间:2024/06/06 03:36
传送门:点击打开链接
题意:长为n的只有数字组成的字符串(n<=5000),问能分割成多少组数字,这些数字里不含前导0,且数字的大小满足严格单调递增
思路:最难的地方,就是如何去快速判断两个数字的大小谁大谁小呢?
我们先来讲下最长公共前缀lcp的定义。如果有串A和串B,lcp[i][j]表示的是串A从原串第i位置开始,串B从原串第j位置开始,那么从这两个位置开始的有多少个字符相等
那么如何来求lcp呢,方程很简单,看了都能懂
lcp[i][j]=lcp[i+1][j+1]+1,if(s[i]==s[j])
lcp[i][j]=0,if(s[i]!=s[j])
求出lcp后如何快速判断两个区间的大数字是否相等呢?
假如lcp[a][b]>=len ,说明两个区间的数字是完全相等的,此时肯定数字是相等的
如果lcp[a][b]<len,那么我们只需要比较s[a+lcp[a][b]]和s[b+lcp[a][b]]的大小就可以了,因为这个位置是两个子串第一个不一样的位置.
知道了这个的话,我们就能再来考虑这道题的dp了。
设dp[i][j](j<=i)表示现在只考虑前i个,最后一个数字是以第j个开头。
那么就能得到转移方程
dp[i][j]+=dp[j-1][k], max(j+1-len,1)<=k<=j-1
dp[i][j]+=dp[j-1][j-len],如果j-len>=1且以j-len开头比以j开头且长度为len数字要小
边界条件是j=1,此时应该等于1
感觉还有地方,,就是写dp的时候总是处理不好边界条件
其实感觉如果就在第二层for里面写if判断边界,这是一种非常好的方法,减少了很多思考,。
#include<map>#include<set>#include<cmath>#include<ctime>#include<stack>#include<queue>#include<cstdio>#include<cctype>#include<string>#include<vector>#include<cstring>#include<iomanip>#include<iostream>#include<algorithm>#include<functional>#define fuck(x) cout<<"["<<x<<"]"#define FIN freopen("input.txt","r",stdin)#define FOUT freopen("output.txt","w+",stdout)using namespace std;typedef long long LL;typedef pair<int, int>PII;const int MX = 5e3 + 5;const int mod = 1e9 + 7;const int INF = 0x3f3f3f3f;char s[MX];short lcp[MX][MX];int n, dp[MX][MX], pre[MX][MX];bool check(int a, int b, int len) { int t = lcp[a][b]; if(t < len && s[a + t] < s[b + t]) return true; return false;}void solve() { memset(lcp, 0, sizeof(lcp)); memset(pre, 0, sizeof(pre)); memset(dp, 0, sizeof(dp)); for(int i = n; i >= 1; i--) { for(int j = n; j >= 1; j--) { if(s[i] == s[j]) lcp[i][j] = lcp[i + 1][j + 1] + 1; else lcp[i][j] = 0; } } for(int i = 1; i <= n; i++) { for(int j = 1; j <= i; j++) { if(s[j] == '0') continue; if(j == 1) dp[i][j] = 1; int len = i - j + 1; int l = max(j + 1 - len, 1), r = j - 1; if(l <= r) dp[i][j] = (pre[j - 1][r] - pre[j - 1][l - 1]) % mod; if(j - len >= 1 && check(j - len, j, len)) { dp[i][j] = (dp[i][j] + dp[j - 1][j - len]) % mod; } } for(int j = 1; j <= i; j++) { pre[i][j] = (pre[i][j - 1] + dp[i][j]) % mod; } } int ans = 0; for(int i = 1; i <= n; i++) { ans = (ans + dp[n][i]) % mod; } printf("%d\n", (ans + mod) % mod);}int main() { //FIN; while(~scanf("%d%s", &n, s + 1)) { solve(); } return 0;}
- lcp+dp Codeforces611D New Year and Ancient Prophecy
- Good Bye 2015 D. New Year and Ancient Prophecy(dp+LCP)
- codeforces GoodBye2015 D.New Year and Ancient Prophecy (dp+lcp+树状数组)
- codeforces-611D-New Year and Ancient Prophecy【lcp+dp】【好题】
- Good Bye 2015 D. New Year and Ancient Prophecy(dp+lcp)
- CodeForces 611 D. New Year and Ancient Prophecy(dp)
- Codeforces 611D New Year and Ancient Prophecy DP
- DP - CF 611D New Year and Ancient Prophecy
- codeforces-Goodbye2015- New Year and Ancient Prophecy
- CF Good Bye 2015 C. New Year and Domino && D. New Year and Ancient Prophecy (DP)
- Codeforces Good Bye 2015 D. New Year and Ancient Prophecy DP
- Codeforces 611D:New Year and Ancient Prophecy DP 分块记录最后一个
- Codeforces 611D New Year And Ancient Prophecy DP+递推式优化
- Good Bye 2015 D. New Year and Ancient Prophecy
- CodeForces 611D New Year and Ancient Prophecy
- Good BYe 2015 D New Year and Ancient Prophecy
- 【Codeforces Good Bye 2015】D. New Year and Ancient Prophecy
- Good Bye 2015 D. New Year and Ancient Prophecy
- double 到 string 的转换
- ubuntu12.04--change socks5 to http by proxy
- ABI和API的区别
- ubuntu12.04解决ssh连不上
- 线性拟合——离群点outliers的处理
- lcp+dp Codeforces611D New Year and Ancient Prophecy
- 2016 新年新气象
- install rpmbuild on rhel/fedora
- LeetCode95 Unique Binary Search Trees II
- kvm raw qcow2 example
- 如何区分控制器的上一个控制器
- 微软ping程序源代码完整版
- maven for package--system error solution
- ubuntu /etc/profile和/etc/environment的比较