Codeforces Round #741 (Div. 2) E. Rescue Niwen! 字符串 + dp
傳送門
文章目錄
- 題意:
- 思路:
題意:
給你一個串sss,定義其擴張串為s1,s1s2,...,s1s2..sn,s2,s2s3,...,sns_1,s_1s_2,...,s_1s_2..s_n,s_2,s_2s_3,...,s_ns1?,s1?s2?,...,s1?s2?..sn?,s2?,s2?s3?,...,sn?,現在讓你從擴張串中選一個最長上升子序列,按照字典序大小比較。
n≤5000n\le5000n≤5000
思路:
首先,可以發現,當選擇一個后綴串sss,由于sss的前綴都在sss的前面,那么sss的所有前綴都可以加入答案中(當合法的時候),那么可以定義狀態dp[i]dp[i]dp[i]表示以iii的后綴為結尾的最長上升子序列,初始dp[i]=n?i+1dp[i]=n-i+1dp[i]=n?i+1。
轉移的時候顯然可以直接從[1,i?1][1,i-1][1,i?1]轉移過來,當前面一個串為ababdababdababd,當前串abdabdabd,ababd<abdababd<abdababd<abd,顯然是可以直接轉移過來的,考慮對答案的貢獻是多少,按照上面說的n?i+1n-i+1n?i+1是算上了abdabdabd所有前綴串,但是a,aba,aba,ab顯然是不合法的,原因就是他與前面ababdababdababd的前綴串重復了,所以我們要減去兩個的最長公共前綴,由于我們是按照字典序嚴格遞增來轉移的,所以重復的只有最長公共前綴這一塊,并不會與前面已經轉移的狀態沖突,直接算的話復雜度O(n3)O(n^3)O(n3),考慮預處理一下。
定義f[i][j]f[i][j]f[i][j]表示分別以i,ji,ji,j為后綴起點的串的最長公共前綴,由于枚舉的是后綴,所以可以倒著來轉移,轉移方程f[i][j]=(f[i+1][j+1]+1)?(s[i]==s[j])f[i][j]=(f[i+1][j+1]+1)*(s[i]==s[j])f[i][j]=(f[i+1][j+1]+1)?(s[i]==s[j]),與最長公共前綴還是有區別的。
求出來fff,那么dpdpdp轉移也比較明顯了,轉移方程dp[i]=max(dp[i],dp[j]+n?i+1?f[i][j])dp[i]=max(dp[i],dp[j]+n-i+1-f[i][j])dp[i]=max(dp[i],dp[j]+n?i+1?f[i][j]),當然轉移前提是s[i+f[i][j]]>s[j+f[i][j]]s[i+f[i][j]]>s[j+f[i][j]]s[i+f[i][j]]>s[j+f[i][j]]。
// Problem: E. Rescue Niwen! // Contest: Codeforces - Codeforces Round #741 (Div. 2) // URL: https://codeforces.com/contest/1562/problem/E // Memory Limit: 512 MB // Time Limit: 2000 ms // // Powered by CP Editor (https://cpeditor.org)//#pragma GCC optimize("Ofast,no-stack-protector,unroll-loops,fast-math") //#pragma GCC target("sse,sse2,sse3,ssse3,sse4.1,sse4.2,avx,avx2,popcnt,tune=native") //#pragma GCC optimize(2) #include<cstdio> #include<iostream> #include<string> #include<cstring> #include<map> #include<cmath> #include<cctype> #include<vector> #include<set> #include<queue> #include<algorithm> #include<sstream> #include<ctime> #include<cstdlib> #include<random> #include<cassert> #define X first #define Y second #define L (u<<1) #define R (u<<1|1) #define pb push_back #define mk make_pair #define Mid ((tr[u].l+tr[u].r)>>1) #define Len(u) (tr[u].r-tr[u].l+1) #define random(a,b) ((a)+rand()%((b)-(a)+1)) #define db puts("---") using namespace std;//void rd_cre() { freopen("d://dp//data.txt","w",stdout); srand(time(NULL)); } //void rd_ac() { freopen("d://dp//data.txt","r",stdin); freopen("d://dp//AC.txt","w",stdout); } //void rd_wa() { freopen("d://dp//data.txt","r",stdin); freopen("d://dp//WA.txt","w",stdout); }typedef long long LL; typedef unsigned long long ULL; typedef pair<int,int> PII;const int N=5010,mod=1e9+7,INF=0x3f3f3f3f; const double eps=1e-6;int n; int f[N][N],dp[N]; char s[N];int main() { // ios::sync_with_stdio(false); // cin.tie(0);int _; scanf("%d",&_);while(_--) {scanf("%d%s",&n,s+1);f[n+1][n+1]=f[n+1][n]=f[n][n+1]=0;for(int i=n;i>=1;i--) {for(int j=n;j>=1;j--) {if(s[i]==s[j]) f[i][j]=f[i+1][j+1]+1;else f[i][j]=0;}}int ans=0;for(int i=1;i<=n;i++) {dp[i]=n-i+1;for(int j=1;j<i;j++) {int len=f[i][j];if(i+len-1>=n||s[i+len]<=s[j+len]) continue;dp[i]=max(dp[i],dp[j]+n-i+1-len);}ans=max(ans,dp[i]);}printf("%d\n",ans);}return 0; } /**/總結
以上是生活随笔為你收集整理的Codeforces Round #741 (Div. 2) E. Rescue Niwen! 字符串 + dp的全部內容,希望文章能夠幫你解決所遇到的問題。