Codeforces Round#201(div1) D. Lucky Common Subsequence

题意:给定两个串,求出两个串的最长公共子序列,要求该公共子序列不包含virus串。

用dp+kmp实现

dp[i][j][k]表示以i结尾的字符串和以j结尾的字符串的公共子序列的长度(其中k表示该公共子序列的与virus的匹配程度)很显然,当k==strlen(virus)时,该公共子序列不是我们所求得

当添加一个字符时,如果失配,这时不能让k直接等于0,而是要用kmp给k一个合理的值。

  1 #include <stdio.h>
  2 #include <string.h>
  3 const int N = 100 + 10;
  4 int dp[N][N][N];
  5 int pre[N][N][N][3];
  6 char s1[N],s2[N],vir[N];
  7 int next[N];
  8 char ans[N];
  9 void makeNext(int n)
 10 {
 11     next[0] = -1;
 12     int i = 0,j=-1;
 13     while(i < n)
 14     {
 15         if(j==-1 || vir[i] == vir[j])
 16         {
 17             i++;
 18             j++;
 19             next[i] = j;
 20         }
 21         else
 22             j = next[j];
 23     }
 24 }
 25 void DP(int x, int y, int z, int x1, int y1, int z1, int val)
 26 {
 27     if(dp[x][y][z] < dp[x1][y1][z1] + val)
 28     {
 29         dp[x][y][z] = dp[x1][y1][z1] + val;//状态转移
 30         //保存路径
 31         pre[x][y][z][0] = x1;
 32         pre[x][y][z][1] = y1;
 33         pre[x][y][z][2] = z1;
 34     }
 35 }
 36 int main()
 37 {
 38     int i,j,k;
 39     scanf("%s%s%s",s1+1,s2+1,vir);
 40     int len1 = strlen(s1+1);
 41     int len2 = strlen(s2+1);
 42     int len3 = strlen(vir);
 43     memset(dp,0,sizeof(dp));
 44     memset(pre,-1,sizeof(pre));
 45     makeNext(len3);
 46     for(i=1; i<=len1; ++i)
 47         for(j=1; j<=len2; ++j)
 48         {
 49             for(k=0; k<len3; ++k)
 50             {
 51                 DP(i,j,k,i-1,j,k,0);//s1[i] != s2[j]时的转移
 52                 DP(i,j,k,i,j-1,k,0);
 53                 if(s1[i] == s2[j])//s1[i] == s2[j]
 54                 {
 55                     if(s1[i] == vir[k])
 56                     {
 57                         DP(i,j,k+1,i-1,j-1,k,1);
 58                     }
 59                     else
 60                     {
 61                         int p = next[k];
 62                         while(p!=-1 && s1[i] != vir[p]) p = next[p];
 63                         if(p==-1)
 64                             p = 0;
 65                         if(s1[i] == vir[p])
 66                             DP(i,j,p+1,i-1,j-1,k,1);
 67                         else
 68                             DP(i,j,p,i-1,j-1,k,1);
 69                     }
 70                 }
 71             }
 72         }
 73     int z;
 74     int Max = -1;
 75     for(k=0; k<len3; ++k)
 76         if(Max < dp[len1][len2][k])
 77         {
 78             Max = dp[len1][len2][k];
 79             z = k;
 80         }
 81     if(Max <= 0)
 82         printf("0\n");
 83     else//根据路径求出最长公共子序列
 84     {
 85         int tMax = Max;
 86         int x = len1,y = len2;
 87         while(pre[x][y][z][0] != -1)
 88         {
 89             int xx = pre[x][y][z][0];
 90             int yy = pre[x][y][z][1];
 91             int zz = pre[x][y][z][2];
 92             if(x-xx==1 && y-yy==1&&s1[x] == s2[y])
 93                 ans[Max--] = s1[x];
 94             x = xx;y=yy;z=zz;
 95         }
 96         for(i=1; i<=tMax; ++i)
 97             printf("%c",ans[i]);
 98         printf("\n");
 99     }
100 }

时间: 2024-11-06 17:19:21

Codeforces Round#201(div1) D. Lucky Common Subsequence的相关文章

Codeforces Round #285 Div1 A and Div2 C

Problem 给一个图G,保证G是一个森林(坑!).图G含有N个点,给出每个点的两个属性:度数(degree).异或和(sum).度数表示该点与多少个点相连,异或和表示与其相连的点的编号的异或和(点编号从0开始,若度数为0则异或和为0).要求求出原图,输出边的个数和每条边两端的顶点. Limits Time Limit(ms): 1000 Memory Limit(MB): 256 N: [1, 2^16] degree: [0, N-1] Solution 由于G是森林,G的每一个连通图一定

Codeforces Round #290 Div1 A

Problem 给N串字符串Si,通常定义字典序大小关系为 'a'<'b'<'c'<......<'y'<'z',现要求重新定义大小关系使得对于任意 i,j(i<j)满足Si <Sj,输出大小关系(一串'a'-'z'的排列),或者输出不存在(任意大小关系都不能满足要求). Limits Time Limit(ms): 2000 Memory Limit(MB): 256 N: 100 |Si|: 100 Solution 用图论方法解决,发现满足拓扑关系.枚举相邻

Codeforces Round #290 Div1 B

Problem 有一只青蛙在x轴上跳,起初在原点,现有N种跳跃技能可以购买,每技能有两属性:跳跃长度Li 以及 花费Ci.若购买了第 i 种技能,则可以从 y 位置跳跃到 y+Li 或者 y-Li 位置,但需花费Ci 元.求最小花费使得青蛙可以跳到每一个整数点上,若无法做到,输出-1. Limits Time Limit(ms): 2000 Memory Limit(MB): 256 N: 300 Li: [1, 10^9] Ci: [1, 10^5] Solution 若购买了n个属性使得青蛙

[Codeforces Round #444 div1] C.DZY Loves Colors 【线段树】

题目链接:CF Round #444 div1 C 题目分析 这道题目是要实现区间赋值的操作,同时还要根据区间中原先的值修改区间上的属性权值. 如果直接使用普通的线段树区间赋值的方法,当一个节点表示的区间完全被要求修改的区间包含时,就直接打上赋值的标记然后 return .但是这样这个节点中每个位置原先的值不同,需要进行的属性权值修改也就不同,是不能直接实现的.如果我们在节点表示的区间被修改的区间包含时,并不直接打标记 return ,而是当节点表示的区间被修改的区间完全包含而且这个节点中的每个

Codeforces Round #117 (Div. 2)---D. Common Divisors

Vasya has recently learned at school what a number's divisor is and decided to determine a string's divisor. Here is what he came up with. String a is the divisor of string b if and only if there exists a positive integer x such that if we write out

Codeforces Round # 555 (Div. 3) C2. Increasing subsequence (complicated version) (贪心)

题目链接:http://codeforces.com/contest/1157/problem/C2 当左右两边数字相同时,需要判断一下取哪边能得到更长的递增序列 #include <iostream> #include <cstring> #include <algorithm> #include <cmath> #include <cstdio> #include <queue> #include <climits>

Codeforces Round #201 (Div. 1) / 346A Alice and Bob

#include <cstdio> #include <algorithm> using namespace std; int gcd(int a,int b) { return b?gcd(b,a%b):a; } int n[100+10]; int main() { int t,maxn = 0; scanf("%d",&t); for(int i=0; i<t; i++) { scanf("%d",&n[i]);

Codeforces Round #391 div1 757F (Dominator Tree)

首先先膜杜教orz 这里简单说一下支配树的概念 支配树是对一个有向图来讲的 规定一个起点s,如果s到v的路径上必须经过某些点u,那么离s最近的点u就是v的支配点 在树上的关系就是,v的父亲是u. 一般图的支配树需要使用tarjan算法,但是如果有向图是没有环的,可以采用另一种做法 按照拓扑序建立支配树,每次加点的时候,枚举能到它的所有点,求它们在当前支配树的最近公共祖先,那个点就是该点的支配点 这个题先建立一个最短路图,易知,这个图是没有环的有向图,所以建立支配树的时候就可以采用以上做法 orz

Codeforces Round #295 Div1 B(Cubes)

Problem Limits TimeLimit(ms):3000 MemoryLimit(MB):256 M∈[1,105] Xi∈[?109,109] Yi∈[0,109] Look up Original Problem From here Solution 一个点可取,当且仅当,把它取了之后,上面的点不会失去平衡而掉下来. 开两个优先队列q1,q2.q1的顶元素最大,q2的顶元素最小,起初把所有可取的点都放入q1,q2,然后,轮流从q1,q2取点,如果访问过了就取下一个,取出点后,判断这