CF611D lcp+dp
本篇博客只是留个辣鸡的自己标记一下,误入的同学请出门左转博客
https://blog.csdn.net/loy_184548/article/details/50865777
代码神马的也是复制啊
#include <bits/stdc++.h> #define mst(a) memset(a,0,sizeof (a)) #define FOR(i,n) for (int i = 0; i < n; i++) #define INF 1e9 #define mod 1000000007 #define eps 1e-10 using namespace std; typedef long long ll; int n; string s; int lcp[5005][5005]; int dp[5005][5005]; //前i长度,最后一个数长度为j的方法数 int sum[5005][5005]; void getLcp() //最长公共前缀lcp { for (int i = n; i > 0; i--) { for (int j = n; j > i; j--) { if (s[i] == s[j]) lcp[i][j] = lcp[i + 1][j + 1] + 1; else lcp[i][j] = 0; } } } bool check(int a,int b) { char ret1 = s[a+lcp[a][b]]; char ret2 = s[b+lcp[a][b]]; if (ret1 < ret2) return true; //满足条件返回1 else return false; } void solve() { for (int i = 0; i <= n; i++) sum[0][i] = 1; //初始化 for (int i = 1 ; i <= n; i++) { for (int j = 1; j <= i; j++) { /*在前面基础上加上一段j长度*/ int len = i - j + 1; //j串的开头位置 if (s[len] == '0') continue; //处理前缀0 /*1.处理前面最后一段比j短的情况(即数字一定比j小)*/ dp[i][j] = sum[len - 1][j - 1]; //sum[i][j]表示前i长度,最后一个长度为小于j的方法总数 /*2.处理前面最后一段和j相等的情况*/ int tmp = len - j; if (tmp < 1) continue; //前面总长度没有j长 if (check(tmp,len) && lcp[tmp][len] < j) //判断j这段是否满足条件 { dp[i][j] = (dp[i][j] + dp[len - 1][j]) % mod; } } for (int j = 1; j <= n; j++) { sum[i][j] = (sum[i][j - 1] + dp[i][j]) % mod; } } } int main(){ cin >> n >> s; s = " " + s; /*求出最长公共前缀lcp,用于快速比较两个数的大小 如果lcp[a][b] >= len,说明两个数字相等 否则比较s[a+lcp[a][b]]和s[b+lcp[a][b]]即可 */ getLcp(); //最长公共前缀lcp solve(); ll ans = 0; for (int i = 1; i <= n; i++) { ans = (ans + dp[n][i]) % mod; } cout << ans << endl; return 0; }