The default answer to LCS(consecutive or non-consecutive) is DP. Recurrence formula can be found at http://en.wikipedia.org/wiki/Longest_common_subsequence_problem . Calculation is O(mn) and printing is O(m+n). But this typical DP algorithm triggers TLE, as many others:

#include <vector> #include <cstdio> #include <string> #include <vector> #include <iostream> using namespace std; ///////////////////////// #define gc getchar int read_int() { char c = gc(); while(c<'0' || c>'9') c = gc(); int ret = 0; while(c>='0' && c<='9') { ret = 10 * ret + c - 48; c = gc(); } return ret; } int read_string(char *p) { int cnt = 0; char c; while((c = gc()) == ' '); // skip spaces // while(c != 10) { p[cnt ++] = c; c = gc(); } return cnt; } ///////////////////////// const int MaxLen = 1000; int lcs[MaxLen][MaxLen]; struct Rec { void init() { bMatch = false; c = '\0'; offI = offJ = 0; } // Match Info bool bMatch; char c; // Offset int offI; int offJ; }; Rec rec[MaxLen][MaxLen]; void clear() { memset(lcs, 0, sizeof(int) * MaxLen * MaxLen); for(int i = 0; i < MaxLen; i ++) for(int j = 0; j < MaxLen; j ++) { rec[i][j].init(); } } void print_path(int lstI, int lstJ) { if(lstI < 0 || lstJ < 0) return; print_path(lstI + rec[lstI][lstJ].offI, lstJ + rec[lstI][lstJ].offJ); if(rec[lstI][lstJ].bMatch) { printf("%c %d %d\n", rec[lstI][lstJ].c, lstI + 1, lstJ + 1); } } void lcs_func(char *p1, int len1, char *p2, int len2) { int maxLen = 0; int currI = 0; int currJ = 0; for(int i = 0; i < len1; i ++) for(int j = 0; j < len2; j ++) { if(p1[i] == p2[j]) { int lst = (i == 0 || j == 0) ? 0 : lcs[i-1][j-1]; lcs[i][j] = lst + 1; rec[i][j].offI = rec[i][j].offJ = -1; rec[i][j].bMatch = true; rec[i][j].c = p1[i]; } else { int lst1 = (i == 0) ? 0 :lcs[i-1][j]; int lst2 = (j == 0) ? 0 :lcs[i][j-1]; int lg = max(lst1, lst2); lcs[i][j] = lg; if(lg == lst1) { rec[i][j].offI = -1; } else if(lg == lst2) { rec[i][j].offJ = -1; } } if(lcs[i][j] > maxLen) { maxLen = lcs[i][j]; currI = i; currJ = j; } } if(maxLen > 1) { printf("Y\n"); printf("%d\n", maxLen == 1 ? 0 : maxLen); print_path(currI, currJ); } else { printf("N\n"); } } ///////////////////////// int main() { int runcnt = read_int(); for(int i = 1; i <= runcnt; i ++) { clear(); int ccnt1 = read_int(); char l1[1024]; read_string(l1); int ccnt2 = read_int(); char l2[1024]; read_string(l2); printf("case %d ", i); lcs_func((char*)l1, ccnt1, (char*)l2, ccnt2); } return 0; }
Well this problem does have a O(nlgn) algorithm: LCS->LIS. We need take special care of consecutive pattern like "aa", "aab"; and, we have to make sure only 1 index is chosen from each sub-seq, like 1, 3, 6, (4, 2) : the last 2 should not be taken into account.

#include <vector> #include <cstdio> #include <map> #include <cstring> #include <string> #include <vector> #include <iostream> #include <algorithm> using namespace std; //////// Fast IO //////// #define gc getchar int read_int() { char c = gc(); while(c<'0' || c>'9') c = gc(); int ret = 0; while(c>='0' && c<='9') { ret = 10 * ret + c - 48; c = gc(); } return ret; } int read_string(char *p) { int cnt = 0; char c; while((c = gc()) == ' '); // skip spaces // while(c != 10) { p[cnt ++] = c; c = gc(); } return cnt; } void print_fast(char *p) { fwrite(p, 1, strlen(p), stdout); } ///////////////////////// const int MaxLen = 1000; struct cInfo { cInfo(char rc, int ri1, int ri2) { set(rc, ri1, ri2); } void set(char rc, int ri1, int ri2) { c = rc; inx1 = ri1; inx2 = ri2; } char c; int inx1; int inx2; }; struct comp_func { bool operator() (const cInfo & left, const cInfo & right) { return left.inx2 < right.inx2; } bool operator() (const cInfo & left, const int & right) { return left.inx2 < right; } bool operator() (const int & left, const cInfo & right) { return left < right.inx2; } }; ///////////////////////// void lcs_func_by_lis(char *p1, int len1, char *p2, int len2) { // Get shorter & longer string bool bS1Longer = len1 > len2; char *s = !bS1Longer ? p1 : p2; int lens = !bS1Longer ? len1 : len2; char *l = bS1Longer ? p1 : p2; int lenl = bS1Longer ? len1 : len2; // Get indices array. vector<int> sInxSet[26]; for(int j = 0; j < lenl; j ++) { sInxSet[l[j]-'a'].push_back(j); } // LIS - Caveat: please make sure there's only one chosen in one seq(..) vector<cInfo> ret; for(int i = 0; i < lens; i ++) { int lstSpot = -1; // to make sure only 1 affects final seq char c = s[i]; vector<int> &vec = sInxSet[c-'a']; for(int j = vec.size() - 1; j >= 0; j --) { vector<cInfo>::iterator iter = upper_bound(ret.begin(), ret.end(), vec[j], comp_func()); if(iter == ret.end()) { ret.push_back(cInfo(c, i, vec[j])); lstSpot = ret.size() - 1; } else { int inx = iter - ret.begin(); if(inx > 0) { if(vec[j] == ret[inx - 1].inx2) break; } bool bOverw = inx == lstSpot; if(lstSpot == -1 || bOverw) { ret[inx].set(c, i, vec[j]); lstSpot = inx; } } } } if(ret.size() <= 1) { printf("N\n"); } else { printf("Y\n"); printf("%d\n", ret.size()); for(unsigned i = 0; i < ret.size(); i ++) { printf("%c %d %d\n", ret[i].c, bS1Longer ? ret[i].inx2 + 1 : ret[i].inx1 + 1, bS1Longer ? ret[i].inx1 + 1 : ret[i].inx2 + 1); } } } ///////////////////////// int main() { int runcnt = read_int(); for(int i = 1; i <= runcnt; i ++) { int ccnt1 = read_int(); char l1[1024]; read_string(l1); int ccnt2 = read_int(); char l2[1024]; read_string(l2); printf("case %d ", i); lcs_func_by_lis((char*)l1, ccnt1, (char*)l2, ccnt2); } return 0; }