• codeforces 1562 E. Rescue Niwen! (dp)


    题目链接:http://codeforces.com/contest/1562/problem/E

    首先考虑贪心,如果选择了从 (i) 开始的字符串,那么选择所有 (i) 开始的字符串一定不会更差

    (dp[i]) 表示以 (i) 开始的字符串为结尾的最长上升子序列的长度,如果可以从 (j(j<i)) 转移过来,那一定存在一个从 (j) 开始的字符串,使得该字符串字典序小于某个从 (i) 开始的字符串,直接判断复杂度是 (O(n)) 的,我们可以考虑求出两两后缀字符串的 (lcp),每次转移时比较 (lcp) 的下一个字符即可

    求所有后缀字符串两两的 (lcp) 可以使用 (dp),设 (dp[i][j]) 表示后缀 (i)(j)(lcp),则 (dp[i][j] = (dp[i+1][j+1]+1)*(s[i]==s[j]))

    时间复杂度 (O(n^2))

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    const int maxn = 5010;
    
    int T, n;
    int lcp[maxn][maxn], dp[maxn];
    char s[maxn];
    
    ll read(){ ll s = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar(); } while(ch >= '0' && ch <= '9'){ s = s * 10 + ch - '0'; ch = getchar(); } return s * f; }
    
    int main(){
    	scanf("%d", &T);
    	while(T--){
    		scanf("%d", &n);
    		scanf("%s", s+1);
    		for(int i = n ; i >= 1 ; --i){
    			for(int j = n ; j >= 1 ; --j){
    				lcp[i][j] = (lcp[i+1][j+1] + 1) * (s[i] == s[j]);
    			}
    		}
    		
    		for(int i = 1 ; i <= n ; ++i){
    			dp[i] = n - i + 1;
    			for(int j = 1 ; j < i ; ++j){
    				if(s[i+lcp[i][j]] > s[j+lcp[i][j]]) dp[i] = max(dp[i], dp[j] + n-i+1-lcp[i][j]);
    			}
    		}
    		
    		int ans = 0;
    		for(int i = 1 ; i <= n ; ++i) ans = max(ans, dp[i]);
    		printf("%d
    ", ans);
    		
    		for(int i = 0 ; i <= n ; ++i) dp[i] = 0;
    		for(int i = 0 ; i <= n + 1 ; ++i){
    			for(int j = 0 ; j <= n + 1 ; ++j) lcp[i][j] = 0;
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    Apahe的安装报错信息:(OS 5)拒绝访问。 : AH00369: Failed to open the Windows service manager, perhaps you forgot to log in as Adminstrator?
    Linux上安装MySQL
    openssh
    脚本基础
    交换分区swap和日志系统
    Linux系统磁盘管理
    网络基础管理
    yum工具的使用
    Linux软件管理
    Linux控制服务和守护进程
  • 原文地址:https://www.cnblogs.com/tuchen/p/15223806.html
Copyright © 2020-2023  润新知