poj3693 Maximum repetition substring

本文探讨了一个字符串中重复次数最多的子串的查找方法,包括输入格式、输出要求及解决策略,通过实例展示了如何利用特定算法高效解决该问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Maximum repetition substring
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 5907 Accepted: 1787

Description

The repetition number of a string is defined as the maximum number R such that the string can be partitioned into R same consecutive substrings. For example, the repetition number of "ababab" is 3 and "ababa" is 1.

Given a string containing lowercase letters, you are to find a substring of it with maximum repetition number.

Input

The input consists of multiple test cases. Each test case contains exactly one line, which
gives a non-empty string consisting of lowercase letters. The length of the string will not be greater than 100,000.

The last test case is followed by a line containing a '#'.

Output

For each test case, print a line containing the test case number( beginning with 1) followed by the substring of maximum repetition number. If there are multiple substrings of maximum repetition number, print the lexicographically smallest one.

Sample Input

ccabababc
daabbccaa
#

Sample Output

Case 1: ababab
Case 2: aa
这题也就是上一题的升级版,保存下来所有的最多重复的长度,再用sa数组从小到大一个一个的找,sa数组刚好保证了是字典序,这样就可以得出答案了!

 
#include <iostream>
#include <stdio.h>
#include <math.h>
#include <string.h>
using namespace std;
#define maxn 1005000
int wa[maxn], wb[maxn], ws[maxn], wv[maxn], wsd[maxn], r[maxn], sa[maxn];
char str[maxn];
#define M 1000100
int dp[M][18];
#define F(x) ((x)/3+((x)%3==1?0:tb))
#define G(x) ((x)<tb?(x)*3+1:((x)-tb)*3+2)
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++) wsd[i] = 0;
  for (i = 0; i < n; i++) wsd[wv[i]]++;
  for (i = 1; i < m; i++) wsd[i] += wsd[i - 1];
  for (i = n - 1; i >= 0; i--) b[--wsd[wv[i]]] = a[i];
  return;
}
void dc3(int *r, int *sa, int n, int m) {
  int i, j, *rn = r + n, *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++];
  return;
}
int cmp(int *r, int a, int b, int l) {
  return r[a] == r[b] && r[a + l] == r[b + l];
}
void da(int *r, int *sa, int n, int m) {
  int i, j, p, *x = wa, *y = wb, *t;
  for (i = 0; i < m; i++) wsd[i] = 0;
  for (i = 0; i < n; i++) wsd[x[i] = r[i]]++;
  for (i = 1; i < m; i++) wsd[i] += wsd[i - 1];
  for (i = n - 1; i >= 0; i--) sa[--wsd[x[i]]] = i;
  for (j = 1, p = 1; p < n; j *= 2, m = p) {
    for (p = 0, i = n - j; i < n; i++) y[p++] = i;
    for (i = 0; i < n; i++) if (sa[i] >= j) y[p++] = sa[i] - j;
    for (i = 0; i < n; i++) wv[i] = x[y[i]];
    //技牢快快
    for (i = 0; i < m; i++) wsd[i] = 0;
    for (i = 0; i < n; i++) wsd[wv[i]]++;
    for (i = 1; i < m; i++) wsd[i] += wsd[i - 1];
    for (i = n - 1; i >= 0; i--) sa[--wsd[wv[i]]] = y[i];
    //技牢快快
    for (t = x, x = y, y = t, p = 1, x[sa[0]] = 0, i = 1; i < n; i++)
      x[sa[i]] = cmp(y, sa[i - 1], sa[i], j) ? p - 1 : p++;
  }
  return;
}
int rank1[maxn], height[maxn];
void calheight(int *r, int *sa, int n) {
  int i, j, k = 0;
  for (i = 1; i <= n; i++) rank1[sa[i]] = i;
  for (i = 0; i < n; height[rank1[i++]] = k)
    for (k ? k-- : 0, j = sa[rank1[i] - 1]; r[i + k] == r[j + k]; k++);
  return;
}
void makermq(int n, int b[]) {
  int i, j;
  for (i = 1; i <= n; i++)
    dp[i][0] = b[i];
  for (j = 1; (1 << j) <= n; j++)
    for (i = 1; i + (1 << j) - 1 <= n; i++)
      dp[i][j] = min(dp[i][j - 1], dp[i + (1 << (j - 1))][j - 1]);
}
int rmq(int s, int v) {
  s = rank1[s], v = rank1[v];
  if (s > v)swap(s, v);
  s++;
  int k = (int) (log((v - s + 1) * 1.0) / log(2.0));
  return min(dp[s][k], dp[v - (1 << k) + 1][k]);
}
int q[M], cnt;
int solve(int n) {
  int i, k, tmp, j, maxx = 1, l, t, jj;
  cnt = 0;
  for (l = 1; l < n; l++)
    for (i = 0; i + l < n; i = i + l) {
      k = rmq(i, i + l);
      t = k / l + 1;
      tmp = i - (l - k % l);
      if (tmp >= 0 && (k % l != 0) && rmq(tmp, tmp + l) >= k)
        t++;
      if (t > maxx) {
        maxx = t;
        cnt = 0;
        q[cnt++] = l;
      }
      if (t == maxx) {
        q[cnt++] = l;
      }
    }
  bool flag = true;
  for (i = 1; i <= n && flag; i++)
    for (j = 0; j < cnt; j++) {
      t = q[j];
      tmp = rmq(sa[i], sa[i] + t);
      if (tmp >= (maxx - 1) * t) {
        l = maxx * t;
        for (k = sa[i], jj = 0; jj < l; jj++) {
          printf("%c", str[k + jj]);
        }
        printf("\n");
        flag = false;
        return 1;
      }
    }
  printf("%c\n", str[0]);
  return 1;
}
int main() {
  int n, n1, i, tcase, t = 1;
  while (scanf("%s", str) != EOF) {
    n = strlen(str);
    if (n == 1 && str[0] == '#')
      break;
    printf("Case %d: ", t++);
    for (i = 0; i < n; i++) {
      r[i] = (int) str[i] + 1;
      rank1[i] = height[i] = 0;
      str[n + i] = str[i];
    }
    int l = n;
    r[n] = 0;
    int m = 300;
    //da(r,sa,n+1,m);
    dc3(r, sa, n + 1, m);
    calheight(r, sa, n);
    makermq(n, height);
    int maxx = solve(n);
  }
  return 0;
}

 

 

 

<think>好的,我现在需要帮助用户找到关于POJ最大和问题的题目或解法。用户提到的是“maximum sum problem”,根据提供的引用,引用[1]里提到了POJ 1481 Maximum sum,动态规划解法。所以首先确定题目编号是1481。 接下来,用户需要解法或问题。根据引用内容,问题描述是给定一组整数,找出两个不重叠的子数组,使得它们的和最大。动态规划的方法被提到,所以需要解释如何用动态规划解决这个问题。 首先,我需要确认问题的大意:找到两个不相交的子数组,使得它们的和最大。这需要分解问题,可能分为两个步骤:先找到从左到右的最大子数组,再找到从右到左的最大子数组,或者类似的方法。 然后,动态规划的思路通常是记录当前最大和,或者前向和后向的最大值。例如,维护两个数组left和right,left[i]表示从0到i的最大子数组和,right[j]表示从j到n-1的最大子数组和。然后遍历所有可能的分割点,计算left[i] + right[i+1]的最大值。 需要确保这两个子数组不重叠,所以分割点必须满足第一个子数组结束在i,第二个开始于i+1之后。因此,可能需要两次遍历,一次从左到右,一次从右到左,存储每个位置的最大值。 然后,编写代码示例,可能使用Python。例如,先计算left数组,再计算right数组,然后遍历所有可能的分割点,找到最大的组合。需要注意数组的索引范围,避免越界。 此外,引用中提到的其他POJ题目资源,如引用[2]和[3]提供了刷题顺序,可能用户对题目难度和顺序也有兴趣,所以可以推荐这些资源,帮助用户按难度练习。 最后,生成相关问题,可能涉及动态规划的其他应用,类似的最大和问题变种,或者POJ题目的推荐顺序。确保问题与用户的需求相关,帮助他们深入理解题目和解法。</think>关于POJ 1481 Maximum sum问题的解法和题目描述如下: ### POJ 1481 Maximum sum问题描述 给定$n$个整数的集合$A=\{a_1, a_2,...,a_n\}$,定义函数$d(A)$为满足以下条件的最大和: $$ d(A) = \max\left\{ \sum_{i=s_1}^{t_1} a_i + \sum_{j=s_2}^{t_2} a_j \ \big| \ 1 \leq s_1 \leq t_1 < s_2 \leq t_2 \leq n \right\} $$ 即寻找两个**不重叠**的子数组,使得它们的和最大[^1]。 --- ### 动态规划解法 #### 核心思路 1. **预处理左右区间最大子段和**: - 用$left[i]$表示从$a_1$到$a_i$区间内的最大子段和 - 用$right[j]$表示从$a_j$到$a_n$区间内的最大子段和 2. **遍历分割点**: 对于每个分割点$k$($1 \leq k < n$),计算$left[k] + right[k+1]$的最大值 #### 算法步骤 1. 正向遍历数组,计算$left$数组(类似最大子段和) 2. 反向遍历数组,计算$right$数组 3. 遍历所有可能的分割点,求最大和 --- ### Python代码实现 ```python def max_sum(arr): n = len(arr) # 计算左半部分最大子段和 left = [0] * n current = left[0] = arr[0] for i in range(1, n): current = max(arr[i], current + arr[i]) left[i] = max(left[i-1], current) # 计算右半部分最大子段和 right = [0] * n current = right[-1] = arr[-1] for i in range(n-2, -1, -1): current = max(arr[i], current + arr[i]) right[i] = max(right[i+1], current) # 寻找最大组合 max_val = -float('inf') for k in range(n-1): max_val = max(max_val, left[k] + right[k+1]) return max_val ``` --- ### POJ题目资源推荐 1. **题目难度列表**:引用[2]提供了POJ从易到难的刷题顺序,适合循序渐进练习 2. **同类问题扩展**:可尝试POJ 2479(Maximum sum进阶版)、POJ 2593(双字段最大和变种) 3. **训练路径**:参考引用[3]的刷题顺序规划,建议先掌握基础动态规划再挑战本题 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值