题目大意:
给定一个字符串 字符为0~9
求翻转某个区间后使得串中的最长不降子序列最长
因为字符范围为0~9
假设有一个 0 1 2 3 4 5 6 7 8 9 的序列
此时翻转某个区间得到形如 0 1 ... L【R R-1 ... L+1 L】R R+1 ... 9 的序列
用这个序列与原串匹配一个最长公共子序列
题解:
https://www.cnblogs.com/ZERO-/p/9493597.html
https://blog.csdn.net/qkoqhh/article/details/81491097
//#include <bits/stdc++.h> //using namespace std; //#define INF 0x3f3f3f3f //#define LL long long //#define mem(i,j) memset(i,j,sizeof(i)) //const int N=1e5+5; // //int n, b[15]; //char str[N]; int a[N]; //int dp[N][15], pre[N][15]; // //int main() //{ // int t; scanf("%d",&t); // while(t--) { // int ans=0,ansl,ansr; scanf("%d%s",&n,str); // for(int i=0;i<n;i++) a[i+1]=str[i]-'0'; // for(int L=1;L<=9;L++) // for(int R=L;R<=9;R++) { // int tot=0; // for(int k=0;k<=L;k++) b[++tot]=k; // for(int k=R;k>=L;k--) b[++tot]=k; // for(int k=R;k<=9;k++) b[++tot]=k; // for(int i=1;i<=n;i++) { // int t=0; // for(int j=1;j<=tot;j++) { // if(dp[i-1][j]>dp[i-1][t]) t=j; // pre[i][j]=t; // dp[i][j]=dp[i-1][t]+(a[i]==b[j]); // } // } // for(int j=tot;j>=1;j--) // if(dp[n][j]>ans) { // ans=dp[n][j]; // int t=j,l=0,r=0; // for(int i=n;i>=0;i--) { // if(!l && t<=L+1) l=i+1; // if(!r && t<=R+2) r=i; // t=pre[i][t]; // } // if(r==0) r=l; // ansl=l,ansr=r; // } // } // printf("%d %d %d ",ans,ansl,ansr); // } // // return 0; //} #include <bits/stdc++.h> using namespace std; #define INF 0x3f3f3f3f #define LL long long #define mem(i,j) memset(i,j,sizeof(i)) const int N=1e5+5; int n, b[15]; char str[N]; int a[N]; int dp[N][15], pre[N][15]; int main(){ int t; scanf("%d",&t); while(t--) { int ansl,ansr,ans=0; scanf("%d%s",&n,str); for(int i=0;i<n;i++) a[i+1]=str[i]-'0'; for(int L=0;L<=9;L++) /// 枚举翻转区间 for(int R=L;R<=9;R++) { int tot=0; for(int i=0;i<=L;i++) b[++tot]=i; for(int i=R;i>=L;i--) b[++tot]=i; for(int i=R;i<=9;i++) b[++tot]=i; for(int i=1;i<=n;i++) { int t=0; for(int j=1;j<=tot;j++) { if(dp[i-1][j]>dp[i-1][t]) t=j; pre[i][j]=t; // 记录前驱在b[]中的位置 dp[i][j]=dp[i-1][t]+(a[i]==b[j]); // 更新LCS长度 } } for(int j=tot;j>=1;j--) if(dp[n][j]>ans) { ans=dp[n][j]; int t=j,l=0,r=0; for(int i=n;i>=0;i--) { // 翻转区间为 0 1 ... L【R R-1 ... L+1 L】R R+1 ... 9 // 所以区间左端l位置实际是在L+1 // 所以区间右端r位置实际是在R+2 if(!l && t<=L+1) l=i+1; if(!r && t<=R+2) r=i; // 当t满足位置条件 才是找到l r t=pre[i][t]; } if(r==0)r=l; ansl=l; ansr=r; } } printf("%d %d %d ",ans,ansl,ansr); } return 0; }