Contest
http://acm.hust.edu.cn/vjudge/contest/view.action?cid=23305#overview
Template
sa[i]=j表示str+i这个字符串在所有后缀中第j小
rank[i]=j表示后缀中第i小的是str+j
rank[i]=j表示后缀中第i小的是str+j
const int N = 5e4 + 9;
namespace Suffix_array{
# define F(x) ((x)/3+((x)%3==1?0:tb))
# define G(x) ((x)<tb?(x)*3+1:((x)-tb)*3+2)
int wa[N * 3] , wb[N * 3] , wv[N * 3] , ws[N * 3];
int c0(int *r, int a, int b){
return r[a] == r[b] && r[a + 1] == r[b + 1] && r[a + 2] == r[b + 2];
}
int c12(int k, int *r, int a, int b){
if (k == 2)
return r[a] < r[b] || r[a] == r[b] && c12(1, r, a + 1, b + 1);
else return r[a] < r[b] || r[a] == r[b] && wv[a + 1] < wv[b + 1];
}
void sort(int *r, int *a, int *b, int n, int m)
{
int i;
for (i = 0; i < n; i++) wv[i] = r[a[i]];
for (i = 0; i < m; i++) ws[i] = 0;
for (i = 0; i < n; i++) ws[wv[i]]++;
for (i = 1; i < m; i++) ws[i] += ws[i-1];
for (i = n-1; i >= 0; i--) b[--ws[wv[i]]] = a[i];
return;
}
void dc3(int *r, int *sa, int n, int m)
{
int i, j, *rn = r + n;
int *san = sa + n, ta = 0, tb = (n + 1) / 3, tbc = 0, p;
r[n] = r[n + 1] = 0;
for (i = 0; i < n; i++) if (i % 3 != 0) wa[tbc++] = i;
sort(r + 2, wa, wb, tbc, m);
sort(r + 1, wb, wa, tbc, m);
sort(r, wa, wb, tbc, m);
for (p = 1, rn[F(wb[0])] = 0, i = 1; i < tbc; i++)
rn[F(wb[i])] = c0(r, wb[i-1], wb[i]) ? p-1 : p++;
if (p < tbc) dc3(rn, san, tbc, p);
else for (i = 0; i < tbc; i++) san[rn[i]] = i;
for (i = 0; i < tbc; i++) if (san[i] < tb) wb[ta++] = san[i] * 3;
if (n % 3 == 1) wb[ta++] = n-1;
sort(r, wb, wa, ta, m);
for (i = 0; i < tbc; i++) wv[wb[i] = G(san[i])] = i;
for (i = 0, j = 0, p = 0; i < ta && j < tbc; p++)
sa[p] = c12(wb[j] % 3, r, wa[i], wb[j]) ? wa[i++] : wb[j++];
for (; i < ta; p++) sa[p] = wa[i++];
for (; j < tbc; p++) sa[p] = wb[j++];
}
//str 和sa 也要三倍
// str 最小是 1
void da(int str[],int sa[],int rank[],int height[],int n,int m)
{
for (int i = n; i < n * 3; i++)
str[i] = 0;
dc3 (str , sa , n + 1 , m);
int i, j, k;
for (i = 0; i < n; i++){
sa[i] = sa[i + 1];
rank[sa[i]] = i;
}
for (i = 0, j = 0, k = 0; i < n; height[rank[i ++]] = k)
if (rank[i] > 0)
for (k ? k--: 0 , j = sa[rank[i]-1];
i + k < n && j + k < n && str[i + k] == str[j + k];
k++);
}
}using namespace Suffix_array;
int A[N] , rank[N] , sa[N] , height[N] , Case;
char str[N];
int f[N][20];
int lent[N];
void lcpinit(int len){
int i , j;
int n = len , k = 1 , l = 0;
RST(f); // 不明白
for(i = 0 ; i < n; ++i){
f[i][0] = height[i];
if (i + 1 > k * 2){
k <<= 1;
l++;
}
lent[i + 1] = l;
}
for(j = 1; (1 << j) - 1 < n ; j++)
for(i = 0 ; i + (1 << j) < n ; i++)
f[i][j] = min(f[i][j - 1] , f[i + (1 << (j - 1))][j - 1]);
}
int lcp(int x , int y){
x = rank[x] , y = rank[y];
if (x > y) swap(x , y);
if (x == y) return x - sa[x];
x++;
int k = lent[y - x + 1];
return min(f[x][k] , f[y - (1 << k) + 1][k]);
}
Step
A Musical Theme
做差,求sa 之后二分+判断
#include <functional>
#include <algorithm>
#include <iostream>
#include <fstream>
#include <sstream>
#include <iomanip>
#include <numeric>
#include <cstring>
#include <cassert>
#include <cstdio>
#include <string>
#include <vector>
#include <bitset>
#include <queue>
#include <stack>
#include <cmath>
#include <ctime>
#include <list>
#include <set>
#include <map>
using namespace std;
#define DO(n) for ( int ____n ## __line__ = n; ____n ## __line__ -- ; )
#define ALL(A) A.begin(), A.end()
#define BSC(A, x) (lower_bound(ALL(A), x) - A.begin())
#define CTN(T, x) (T.find(x) != T.end())
#define SZ(A) int(A.size())
#define PB push_back
#define MP(A, B) make_pair(A, B)
#define fi first
#define se second
typedef long long LL;
typedef vector<int> VI;
typedef map<int, int> MII;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
template<class T> inline void RST(T &A){memset(A, 0, sizeof(A));}
template<class T> inline void FLC(T &A, int x){memset(A, x, sizeof(A));}
template<class T> inline void CLR(T &A){A.clear();}
//}
/** Constant List .. **/ //{
const int dx4[] = {-1, 0, 1, 0};
const int dy4[] = {0, 1, 0, -1};
const int dx8[] = {-1, 0, 1, 0 , -1 , -1 , 1 , 1};
const int dy8[] = {0, 1, 0, -1 , -1 , 1 , -1 , 1};
const int dxhorse[] = {-2 , -2 , -1 , -1 , 1 , 1 , 2 , 2};
const int dyhorse[] = {1 , -1 , 2 , -2 , 2 ,-2 , 1 ,-1};
const int MOD = 1000000007;
//int MOD = 99990001;
const int INF = 0x3f3f3f3f;
const LL INFF = 1LL << 60;
const double EPS = 1e-9;
const double OO = 1e15;
const double PI = acos(-1.0); //M_PI;
//}
template<class T> inline void checkMin(T &a,const T b){if (b<a) a=b;}
template<class T> inline void checkMax(T &a,const T b){if (a<b) a=b;}
//}
template<class T> inline T low_bit(T x) {return x & -x;}
/*****************************************************************/
const int N = 3e5+10;
namespace Suffix_array{
# define F(x) ((x)/3+((x)%3==1?0:tb))
# define G(x) ((x)<tb?(x)*3+1:((x)-tb)*3+2)
int wa[N * 3] , wb[N * 3] , wv[N * 3] , ws[N * 3];
int c0(int *r, int a, int b){
return r[a] == r[b] && r[a + 1] == r[b + 1] && r[a + 2] == r[b + 2];
}
int c12(int k, int *r, int a, int b){
if (k == 2)
return r[a] < r[b] || r[a] == r[b] && c12(1, r, a + 1, b + 1);
else return r[a] < r[b] || r[a] == r[b] && wv[a + 1] < wv[b + 1];
}
void sort(int *r, int *a, int *b, int n, int m)
{
int i;
for (i = 0; i < n; i++) wv[i] = r[a[i]];
for (i = 0; i < m; i++) ws[i] = 0;
for (i = 0; i < n; i++) ws[wv[i]]++;
for (i = 1; i < m; i++) ws[i] += ws[i-1];
for (i = n-1; i >= 0; i--) b[--ws[wv[i]]] = a[i];
return;
}
void dc3(int *r, int *sa, int n, int m)
{
int i, j, *rn = r + n;
int *san = sa + n, ta = 0, tb = (n + 1) / 3, tbc = 0, p;
r[n] = r[n + 1] = 0;
for (i = 0; i < n; i++) if (i % 3 != 0) wa[tbc++] = i;
sort(r + 2, wa, wb, tbc, m);
sort(r + 1, wb, wa, tbc, m);
sort(r, wa, wb, tbc, m);
for (p = 1, rn[F(wb[0])] = 0, i = 1; i < tbc; i++)
rn[F(wb[i])] = c0(r, wb[i-1], wb[i]) ? p-1 : p++;
if (p < tbc) dc3(rn, san, tbc, p);
else for (i = 0; i < tbc; i++) san[rn[i]] = i;
for (i = 0; i < tbc; i++) if (san[i] < tb) wb[ta++] = san[i] * 3;
if (n % 3 == 1) wb[ta++] = n-1;
sort(r, wb, wa, ta, m);
for (i = 0; i < tbc; i++) wv[wb[i] = G(san[i])] = i;
for (i = 0, j = 0, p = 0; i < ta && j < tbc; p++)
sa[p] = c12(wb[j] % 3, r, wa[i], wb[j]) ? wa[i++] : wb[j++];
for (; i < ta; p++) sa[p] = wa[i++];
for (; j < tbc; p++) sa[p] = wb[j++];
}
//str 和sa 也要三倍
// str 最小是 1
void da(int str[],int sa[],int rank[],int height[],int n,int m)
{
for (int i = n; i < n * 3; i++)
str[i] = 0;
dc3 (str , sa , n + 1 , m);
int i, j, k;
for (i = 0; i < n; i++){
sa[i] = sa[i + 1];
rank[sa[i]] = i;
}
for (i = 0, j = 0, k = 0; i < n; height[rank[i ++]] = k)
if (rank[i] > 0)
for (k ? k--: 0 , j = sa[rank[i]-1];
i + k < n && j + k < n && str[i + k] == str[j + k];
k++);
}
}using namespace Suffix_array;
//int f[N][20];
//int lent[N];
//void lcpinit(int len){
// int i , j;
// int n = len , k = 1 , l = 0;
// RST(f); /// 不明白。。。。
// for(i = 0 ; i < n; ++i){
// f[i][0] = height[i];
// if (i + 1 > k * 2){
// k <<= 1;
// l++;
// }
// lent[i + 1] = l;
// }
// for(j = 1; (1 << j) - 1 < n ; j++)
// for(i = 0 ; i + (1 << j) < n ; i++)
// f[i][j] = min(f[i][j - 1] , f[i + (1 << (j - 1))][j - 1]);
//}
//int lcp(int x , int y){
// if (x > y) swap(x , y);
// if (x == y) return x - sa[x];
// x++;
// int k = lent[y - x + 1];
// return min(f[x][k] , f[y - (1 << k) + 1][k]);
//}
int n;
int A[N] , sa[N * 3], rank[N * 3] , height[N * 3];
bool check(int x){
int low = sa[0] , high = sa[0];
for (int i = 1; i < n; ++i){
if (height[i] >= x){
checkMin(low , sa[i]);
checkMax(high , sa[i]);
if (high - low >= x) return true;
}
else{
low = sa[i];
high = sa[i];
}
}
return false;
}
void solve(){
for (int i = 0 ; i < n; ++i) scanf("%d" , &A[i]);
int o = 1;
for (int i = 0; i < n - 1 ; ++i){
A[i] = A[i] - A[i + 1];
checkMin(o , A[i]);
}
n--;
for (int i = 0 ; i < n ; ++i) {
A[i] -= o - 1;
// printf("%d " , A[i]);
}
// puts("");
da(A , sa , rank , height , n , 256);
// for (int i = 0 ; i <= n; ++i) cout<< height[i] << endl;
int low = 0 , high = n , ans = low , mid;
do{
mid = low + high >> 1;
if (check(mid)){
checkMax(ans , mid);
low = mid + 1;
}
else high = mid - 1;
}while(low <= high);
if (ans < 4) puts("0");
else printf("%d\n" , ans + 1);
}
int main(){
while(~scanf("%d" , &n) , n) solve();
}
B Milk Patterns
可以二分 + 验证
我用 lcp 正好验证一下模板
#include <functional>
#include <algorithm>
#include <iostream>
#include <fstream>
#include <sstream>
#include <iomanip>
#include <numeric>
#include <cstring>
#include <cassert>
#include <cstdio>
#include <string>
#include <vector>
#include <bitset>
#include <queue>
#include <stack>
#include <cmath>
#include <ctime>
#include <list>
#include <set>
#include <map>
using namespace std;
#define DO(n) for ( int ____n ## __line__ = n; ____n ## __line__ -- ; )
#define ALL(A) A.begin(), A.end()
#define BSC(A, x) (lower_bound(ALL(A), x) - A.begin())
#define CTN(T, x) (T.find(x) != T.end())
#define SZ(A) int(A.size())
#define PB push_back
#define MP(A, B) make_pair(A, B)
#define fi first
#define se second
typedef long long LL;
typedef vector<int> VI;
typedef map<int, int> MII;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
template<class T> inline void RST(T &A){memset(A, 0, sizeof(A));}
template<class T> inline void FLC(T &A, int x){memset(A, x, sizeof(A));}
template<class T> inline void CLR(T &A){A.clear();}
//}
/** Constant List .. **/ //{
const int dx4[] = {-1, 0, 1, 0};
const int dy4[] = {0, 1, 0, -1};
const int dx8[] = {-1, 0, 1, 0 , -1 , -1 , 1 , 1};
const int dy8[] = {0, 1, 0, -1 , -1 , 1 , -1 , 1};
const int dxhorse[] = {-2 , -2 , -1 , -1 , 1 , 1 , 2 , 2};
const int dyhorse[] = {1 , -1 , 2 , -2 , 2 ,-2 , 1 ,-1};
const int MOD = 1000000007;
//int MOD = 99990001;
const int INF = 0x3f3f3f3f;
const LL INFF = 1LL << 60;
const double EPS = 1e-9;
const double OO = 1e15;
const double PI = acos(-1.0); //M_PI;
//}
template<class T> inline void checkMin(T &a,const T b){if (b<a) a=b;}
template<class T> inline void checkMax(T &a,const T b){if (a<b) a=b;}
//}
template<class T> inline T low_bit(T x) {return x & -x;}
/*****************************************************************/
const int N = 3e5+10;
namespace Suffix_array{
# define F(x) ((x)/3+((x)%3==1?0:tb))
# define G(x) ((x)<tb?(x)*3+1:((x)-tb)*3+2)
int wa[N * 3] , wb[N * 3] , wv[N * 3] , ws[N * 3];
int c0(int *r, int a, int b){
return r[a] == r[b] && r[a + 1] == r[b + 1] && r[a + 2] == r[b + 2];
}
int c12(int k, int *r, int a, int b){
if (k == 2)
return r[a] < r[b] || r[a] == r[b] && c12(1, r, a + 1, b + 1);
else return r[a] < r[b] || r[a] == r[b] && wv[a + 1] < wv[b + 1];
}
void sort(int *r, int *a, int *b, int n, int m)
{
int i;
for (i = 0; i < n; i++) wv[i] = r[a[i]];
for (i = 0; i < m; i++) ws[i] = 0;
for (i = 0; i < n; i++) ws[wv[i]]++;
for (i = 1; i < m; i++) ws[i] += ws[i-1];
for (i = n-1; i >= 0; i--) b[--ws[wv[i]]] = a[i];
return;
}
void dc3(int *r, int *sa, int n, int m)
{
int i, j, *rn = r + n;
int *san = sa + n, ta = 0, tb = (n + 1) / 3, tbc = 0, p;
r[n] = r[n + 1] = 0;
for (i = 0; i < n; i++) if (i % 3 != 0) wa[tbc++] = i;
sort(r + 2, wa, wb, tbc, m);
sort(r + 1, wb, wa, tbc, m);
sort(r, wa, wb, tbc, m);
for (p = 1, rn[F(wb[0])] = 0, i = 1; i < tbc; i++)
rn[F(wb[i])] = c0(r, wb[i-1], wb[i]) ? p-1 : p++;
if (p < tbc) dc3(rn, san, tbc, p);
else for (i = 0; i < tbc; i++) san[rn[i]] = i;
for (i = 0; i < tbc; i++) if (san[i] < tb) wb[ta++] = san[i] * 3;
if (n % 3 == 1) wb[ta++] = n-1;
sort(r, wb, wa, ta, m);
for (i = 0; i < tbc; i++) wv[wb[i] = G(san[i])] = i;
for (i = 0, j = 0, p = 0; i < ta && j < tbc; p++)
sa[p] = c12(wb[j] % 3, r, wa[i], wb[j]) ? wa[i++] : wb[j++];
for (; i < ta; p++) sa[p] = wa[i++];
for (; j < tbc; p++) sa[p] = wb[j++];
}
//str 和sa 也要三倍
// str 最小是 1
void da(int str[],int sa[],int rank[],int height[],int n,int m)
{
for (int i = n; i < n * 3; i++)
str[i] = 0;
dc3 (str , sa , n + 1 , m);
int i, j, k;
for (i = 0; i < n; i++){
sa[i] = sa[i + 1];
rank[sa[i]] = i;
}
for (i = 0, j = 0, k = 0; i < n; height[rank[i ++]] = k)
if (rank[i] > 0)
for (k ? k--: 0 , j = sa[rank[i]-1];
i + k < n && j + k < n && str[i + k] == str[j + k];
k++);
}
}using namespace Suffix_array;
int n;
int A[N] , sa[N * 3], rank[N * 3] , height[N * 3];
int f[N][20];
int lent[N];
void lcpinit(int len){
int i , j;
int n = len , k = 1 , l = 0;
for(i = 0 ; i < n; ++i){
f[i][0] = height[i];
if (i + 1 > k * 2){
k <<= 1;
l++;
}
lent[i + 1] = l;
}
for(j = 1; (1 << j) - 1 < n ; j++)
for(i = 0 ; i + (1 << j) - 1 < n ; i++)
f[i][j] = min(f[i][j - 1] , f[i + (1 << (j - 1))][j - 1]);
}
int lcp(int x , int y){
if (x > y) swap(x , y);
if (x == y) return x - sa[x];
x++;
int k = lent[y - x + 1];
return min(f[x][k] , f[y - (1 << k) + 1][k]);
}
int K;
void solve(){
for (int i = 0 ; i < n; ++i) scanf("%d" , &A[i]);
// puts("");
da(A , sa , rank , height , n , 256);
// for (int i = 0 ; i <= n; ++i) cout<< sa[i] << endl;
lcpinit(n );
int ans = 0;
for (int i = 0 ; i + K - 1 < n ; ++i){
// printf("%d %d\n", i , lcp(i , i + K - 2));
checkMax(ans , lcp(i , i + K - 1));
}
printf("%d\n" , ans);
}
int main(){
while(~scanf("%d%d" , &n , &K)) solve();
}
E Palindrome
求最长回文串,如果有多个输出第一个。。
注意 ABCDEFDCBA 答案不是 ABCD 的问题。。
于是乎要对于 sa 的位置做个判断
#include <functional>
#include <algorithm>
#include <iostream>
#include <fstream>
#include <sstream>
#include <iomanip>
#include <numeric>
#include <cstring>
#include <cassert>
#include <cstdio>
#include <string>
#include <vector>
#include <bitset>
#include <queue>
#include <stack>
#include <cmath>
#include <ctime>
#include <list>
#include <set>
#include <map>
using namespace std;
#define DO(n) for ( int ____n ## __line__ = n; ____n ## __line__ -- ; )
#define ALL(A) A.begin(), A.end()
#define BSC(A, x) (lower_bound(ALL(A), x) - A.begin())
#define CTN(T, x) (T.find(x) != T.end())
#define SZ(A) int(A.size())
#define PB push_back
#define MP(A, B) make_pair(A, B)
#define fi first
#define se second
typedef long long LL;
typedef vector<int> VI;
typedef map<int, int> MII;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
template<class T> inline void RST(T &A){memset(A, 0, sizeof(A));}
template<class T> inline void FLC(T &A, int x){memset(A, x, sizeof(A));}
template<class T> inline void CLR(T &A){A.clear();}
//}
/** Constant List .. **/ //{
const int dx4[] = {-1, 0, 1, 0};
const int dy4[] = {0, 1, 0, -1};
const int dx8[] = {-1, 0, 1, 0 , -1 , -1 , 1 , 1};
const int dy8[] = {0, 1, 0, -1 , -1 , 1 , -1 , 1};
const int dxhorse[] = {-2 , -2 , -1 , -1 , 1 , 1 , 2 , 2};
const int dyhorse[] = {1 , -1 , 2 , -2 , 2 ,-2 , 1 ,-1};
const int MOD = 1000000007;
//int MOD = 99990001;
const int INF = 0x3f3f3f3f;
const LL INFF = 1LL << 60;
const double EPS = 1e-9;
const double OO = 1e15;
const double PI = acos(-1.0); //M_PI;
//}
template<class T> inline void checkMin(T &a,const T b){if (b<a) a=b;}
template<class T> inline void checkMax(T &a,const T b){if (a<b) a=b;}
//}
template<class T> inline T low_bit(T x) {return x & -x;}
/*****************************************************************/
const int N = 3e5+10;
namespace Suffix_array{
# define F(x) ((x)/3+((x)%3==1?0:tb))
# define G(x) ((x)<tb?(x)*3+1:((x)-tb)*3+2)
int wa[N * 3] , wb[N * 3] , wv[N * 3] , ws[N * 3];
int c0(int *r, int a, int b){
return r[a] == r[b] && r[a + 1] == r[b + 1] && r[a + 2] == r[b + 2];
}
int c12(int k, int *r, int a, int b){
if (k == 2)
return r[a] < r[b] || r[a] == r[b] && c12(1, r, a + 1, b + 1);
else return r[a] < r[b] || r[a] == r[b] && wv[a + 1] < wv[b + 1];
}
void sort(int *r, int *a, int *b, int n, int m)
{
int i;
for (i = 0; i < n; i++) wv[i] = r[a[i]];
for (i = 0; i < m; i++) ws[i] = 0;
for (i = 0; i < n; i++) ws[wv[i]]++;
for (i = 1; i < m; i++) ws[i] += ws[i-1];
for (i = n-1; i >= 0; i--) b[--ws[wv[i]]] = a[i];
return;
}
void dc3(int *r, int *sa, int n, int m)
{
int i, j, *rn = r + n;
int *san = sa + n, ta = 0, tb = (n + 1) / 3, tbc = 0, p;
r[n] = r[n + 1] = 0;
for (i = 0; i < n; i++) if (i % 3 != 0) wa[tbc++] = i;
sort(r + 2, wa, wb, tbc, m);
sort(r + 1, wb, wa, tbc, m);
sort(r, wa, wb, tbc, m);
for (p = 1, rn[F(wb[0])] = 0, i = 1; i < tbc; i++)
rn[F(wb[i])] = c0(r, wb[i-1], wb[i]) ? p-1 : p++;
if (p < tbc) dc3(rn, san, tbc, p);
else for (i = 0; i < tbc; i++) san[rn[i]] = i;
for (i = 0; i < tbc; i++) if (san[i] < tb) wb[ta++] = san[i] * 3;
if (n % 3 == 1) wb[ta++] = n-1;
sort(r, wb, wa, ta, m);
for (i = 0; i < tbc; i++) wv[wb[i] = G(san[i])] = i;
for (i = 0, j = 0, p = 0; i < ta && j < tbc; p++)
sa[p] = c12(wb[j] % 3, r, wa[i], wb[j]) ? wa[i++] : wb[j++];
for (; i < ta; p++) sa[p] = wa[i++];
for (; j < tbc; p++) sa[p] = wb[j++];
}
//str 和sa 也要三倍
// str 最小是 1
void da(int str[],int sa[],int rank[],int height[],int n,int m)
{
for (int i = n; i < n * 3; i++)
str[i] = 0;
dc3 (str , sa , n + 1 , m);
int i, j, k;
for (i = 0; i < n; i++){
sa[i] = sa[i + 1];
rank[sa[i]] = i;
}
for (i = 0, j = 0, k = 0; i < n; height[rank[i ++]] = k)
if (rank[i] > 0)
for (k ? k--: 0 , j = sa[rank[i]-1];
i + k < n && j + k < n && str[i + k] == str[j + k];
k++);
}
}using namespace Suffix_array;
//int f[N][20];
//int lent[N];
//void lcpinit(int len){
// int i , j;
// int n = len , k = 1 , l = 0;
// for(i = 0 ; i < n; ++i){
// f[i][0] = height[i];
// if (i + 1 > k * 2){
// k <<= 1;
// l++;
// }
// lent[i + 1] = l;
// }
// for(j = 1; (1 << j) - 1 < n ; j++)
// for(i = 0 ; i + (1 << j) < n ; i++)
// f[i][j] = min(f[i][j - 1] , f[i + (1 << (j - 1))][j - 1]);
//}
//int lcp(int x , int y){
// if (x > y) swap(x , y);
// if (x == y) return x - sa[x];
// x++;
// int k = lent[y - x + 1];
// return min(f[x][k] , f[y - (1 << k) + 1][k]);
//}
int A[N] , rank[N] , sa[N] , height[N];
char str[N];
void solve(){
int n = strlen(str);
int m = n;
str[n++] = '$';
for (int i = 0 ; i < m ; ++i) str[n++] = str[m - i - 1];
str[n++] = 0;
for (int i = 0 ; i < n ; ++i) A[i] = str[i];
da(A , sa , rank , height , n , 256);
int ans = 0 , now = INF;
for (int i = 1 ; i < n; ++i){
//cout << height[i] << endl;
if (sa[i - 1] < m && sa[i] > m || sa[i - 1] > m && sa[i] < m){
int p = sa[i - 1] , q = sa[i];
// if (p > m) p -= m;
// if (q > m) q -= m;
p += height[i] - 1;
// printf("%d-%d-%d\n" , p , m , q);
if (m * 2 != p + q) continue;
if (height[i] > ans){
ans = height[i];
now = min(sa[i - 1] , sa[i]);
}
else if (height[i] == ans){
//cout << min(sa[i - 1] , sa[i]) << endl;
checkMin(now , min(sa[i - 1] , sa[i]));
}
}
}
//cout << ans << endl;
if (ans == 1) putchar(str[0]);
else for (int i = 0 ; i < ans ; ++i) putchar(str[now + i]);
puts("");
}
int main(){
while(~scanf("%s" , str))solve();
}
G - Maximum repetition substring
求字典序最小的 重复次数最多的 子串。。。
好难的一个题目。
int A[N] , rank[N] , sa[N] , height[N] , Case;
char str[N];
int f[N][20];
int lent[N];
void lcpinit(int len){
int i , j;
int n = len , k = 1 , l = 0;
for(i = 0 ; i < n; ++i){
f[i][0] = height[i];
if (i + 1 > k * 2){
k <<= 1;
l++;
}
lent[i + 1] = l;
}
for(j = 1; (1 << j) - 1 < n ; j++)
for(i = 0 ; i + (1 << j) < n ; i++)
f[i][j] = min(f[i][j - 1] , f[i + (1 << (j - 1))][j - 1]);
}
int lcp(int x , int y){
x = rank[x] , y = rank[y];
if (x > y) swap(x , y);
if (x == y) return x - sa[x];
x++;
int k = lent[y - x + 1];
return min(f[x][k] , f[y - (1 << k) + 1][k]);
}
void solve(){
printf("Case %d: " , ++Case);
int n = strlen(str);
for (int i = 0 ; i < n ; ++i) A[i] = str[i];
da(A , sa , rank , height , n , 256);
lcpinit(n);
VI ans;
ans.clear();
int mx = -1;
for (int L = 1 ; L < n ; ++L){
for (int i = 0 ; i + L < n ; i += L){
int K = lcp(i , i + L);
int R = K / L + 1;
int t = L - K % L;
t = i - t;
if (t >= 0 && K % L != 0){
if (lcp(t , t + L) >= K) R++;
}
if (R > mx){
ans.clear();
mx = R;
ans.PB(L);
}
if (R == mx)
ans.PB(L);
}
}
// cout << ans.size() <<endl;
int start , b = 0 , c = 0;
for (int i = 0 ; i < n && !b ; ++i){
for (int j = 0 ; j < ans.size() ; ++j){
int tl = ans[j];
if (lcp(sa[i] , sa[i] + tl) >= (mx - 1) * tl){
start = sa[i];
c = tl * mx;
b = 1;
break;
}
}
}
// cout << c << endl;
for (int i = 0 ; i < c ; ++i) putchar(str[start + i]);
puts("");
}
int main(){
Case = 0;
while(~scanf("%s" , str) , str[0] != '#')solve();
}
L - Life Forms
把这题 1Y 了爽爽爽。。。
这题绝对能增加对于 SA 的理解好么。。。
题意: 多字符串,求所有 在 > n/2 串中出现的公共子串,字典序输出。
解法:
全部连起来,二分答案。利用两个 vector 滚动求解。
要注意的是——一定要用 sa[i] 不是 sa[i - 1] 也不是 i
int belongs[N * 3];
int END[N];
char str[N];
int n , m;
bool occupy[200];
int usesolve;
VI out[2];
bool check(int len){
int sum = 1;
RST(occupy);
occupy[belongs[sa[0]]] = 1;
out[usesolve].clear();
for (int i = 1 ; i < m ; ++i){
if (height[i] >= len){
if (!occupy[belongs[sa[i]]]){
occupy[belongs[sa[i]]] = 1;
++sum;
}
}
else{
if (sum * 2 > n)
out[usesolve].PB(sa[i - 1]);
sum = 1;
RST(occupy);
occupy[belongs[sa[i]]] = 1;
}
}
if (sum * 2 > n) out[usesolve].PB(sa[m - 1]);
return SZ(out[usesolve]);
}
int ans;
void output(){
usesolve ^= 1;
int sz = SZ(out[usesolve]);
for (int i = 0 ; i < sz ; ++i){
for (int j = 0 ; j < ans ; ++j) printf("%c" , A[j + out[usesolve][i]]);
puts("");
}
}
void makebelongs(){
for (int i = 0 ; i < m ; ++i){
int res = lower_bound(END , END + n + 1 , sa[i]) - END;
belongs[sa[i]] = res;
}
}
void solve(){
m = 0;
out[0].clear() , out[1].clear();
usesolve = 0;
for (int i = 0 ; i < n ; ++i){
scanf("%s" , str);
int len = strlen(str);
for (int j = 0 ; j < len ; ++j)
A[ m ++ ] = str[j];
END[i] = m;
A[ m ++ ] = max( 'Z' , 'z' ) + 1 + i;
}
da(A , sa , rank , height , m , 256);
END[n] = INF;
makebelongs();
int low = 0 , high = m , mid;
ans = 0 ;
do{
mid = low + high >> 1;
if (check(mid)){
if (ans < mid){
usesolve ^= 1;
ans = mid;
}
low = mid + 1;
}
else high = mid - 1;
}while(low <= high);
if (ans == 0){
puts("?");
return;
}
output();
}
int main(){
// freopen("0.in" , "r" , stdin);
bool first = true;
while(scanf("%d" , &n) , n){
if (!first) puts("");
first = false;
solve();
}
}
K - Common Substrings
题意:
求公共子串对数。
解法:
连起来,DA 。 利用单调栈[记录一个pair<LCP , cnt>] 来维护。
先用 A 扫 B 再用 B 扫 A。
具体虽然 AC 了还不是很明白,[[[[ height[i + 1] 的原因。。。
先贴代码日后想
namespace List{
PLL st[N]; LL sum;
int top;
void init(){
top = 0;
sum = 0;
}
void push(LL x , LL cnt){
if (x <= 0){
top = 0;
sum = 0;
cnt = 0;
return;
}
sum += x * cnt;
while(top && st[top - 1].fi >= x){
sum -= (st[top - 1].fi - x) * st[top - 1].se;
cnt += st[top - 1].se;
top--;
}
st[top].fi = x;
st[top].se = cnt;
top++;
}
};
int belongs[N * 3];
int k;
char str[N];
int lenpre , m;
void makebelongs(){
for (int i = 0 ; i < m ; ++i)
if (sa[i] <= lenpre) belongs[sa[i]] = 0;
else belongs[sa[i]] = 1;
}
void solve(){
scanf("%s", str);
int len = strlen(str);
m = 0;
for (int i = 0 ; i < len ; ++i)
A[m++] = str[i];
A[m++] = '$';
lenpre = m - 1;
scanf("%s" , str);
for (int i = 0 ; i < len ; ++i)
A[m++] = str[i];
da(A , sa , rank , height , m , 256);
height[m] = 0;
makebelongs();
LL ans = 0;
/**
A 扫 B
*/
List :: init();
for (int i = 1 ; i < m ; ++i){
if (belongs[sa[i]] == 1) ans += List :: sum;
if (belongs[sa[i]] == 0) List :: push(height[i + 1] - k + 1 , 1);
if (belongs[sa[i]] == 1) List :: push(height[i + 1] - k + 1 , 0);
}
/**
B 扫 A
*/
List :: init();
for (int i = 1 ; i < m ; ++i){
if (belongs[sa[i]] == 0) ans += List :: sum;
if (belongs[sa[i]] == 1) List :: push(height[i + 1] - k + 1 , 1);
if (belongs[sa[i]] == 0) List :: push(height[i + 1] - k + 1 , 0);
}
printf("%I64d\n" , ans);
}
int main(){
// freopen("0.in" , "r" , stdin);
// freopen("0.out" , "w" , stdout);
while(scanf("%d" , &k) , k) solve();
}
总结:
SA 好神奇!马上要到赛季了,加油思密达!!!