【HDOJ】3518 Boring Counting

后缀数组2倍增可解。

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <cstdlib>
  4
  5 #define MAXN 1005
  6 #define INF 0xfffff
  7 #define MAXM 27
  8
  9 int wa[MAXN], wb[MAXN], ws[MAXN], wv[MAXN];
 10 char s[MAXN];
 11 int str[MAXN], sa[MAXN];
 12 int height[MAXN], rank[MAXN];
 13
 14 int max(int a, int b) {
 15     return a>b ? a:b;
 16 }
 17
 18 int min(int a, int b) {
 19     return a<b ? a:b;
 20 }
 21
 22 int cmp(int *r, int a, int b, int l) {
 23     return r[a]==r[b] && r[a+l]==r[b+l];
 24 }
 25
 26 void da(int *r, int *sa, int n, int m) {
 27     int i, j, *x = wa, *y = wb, *t;
 28     int p;
 29
 30     for (i=0; i<m; ++i) ws[i] = 0;
 31     for (i=0; i<n; ++i) ws[x[i]=r[i]]++;
 32     for (i=1; i<m; ++i) ws[i] += ws[i-1];
 33     for (i=n-1; i>=0; --i) sa[--ws[x[i]]] = i;
 34     for (j=1, p=1; j<n; j*=2, m=p) {
 35         for (p=0, i=n-j; i<n; ++i) y[p++] = i;
 36         for (i=0; i<n; ++i) if (sa[i] >= j) y[p++] = sa[i] - j;
 37         for (i=0; i<n; ++i) wv[i] = x[y[i]];
 38         for (i=0; i<m; ++i) ws[i] = 0;
 39         for (i=0; i<n; ++i) ws[wv[i]]++;
 40         for (i=1; i<m; ++i) ws[i] += ws[i-1];
 41         for (i=n-1; i>=0; --i) sa[--ws[wv[i]]] = y[i];
 42         for (t=x, x=y, y=t, p=1, x[sa[0]]=0, i=1; i<n; ++i)
 43             x[sa[i]] = cmp(y, sa[i-1], sa[i], j) ? p-1 : p++;
 44     }
 45 }
 46
 47 void calheight(int *r, int *sa, int n) {
 48     int i, j, k = 0;
 49
 50     for (i=1; i<=n; ++i) rank[sa[i]] = i;
 51     for (i=0; i<n; height[rank[i++]]=k)
 52         for (k? --k:0, j=sa[rank[i]-1]; r[i+k]==r[j+k]; ++k)
 53             /*do nothing*/;
 54 }
 55
 56 int getRepeat(int len, int n) {
 57     int i, maxx, minn;
 58     int ret = 0;
 59
 60     maxx = -1;
 61     minn = INF;
 62
 63     for (i=1; i<=n; ++i) {
 64         if (height[i] >= len) {
 65             maxx = max(sa[i], max(sa[i-1], maxx));
 66             minn = min(sa[i], min(sa[i-1], minn));
 67         } else {
 68             if (maxx!=-1 && minn!=INF && (maxx-minn)>=len)
 69                 ++ret;
 70             maxx = -1;
 71             minn = INF;
 72         }
 73     }
 74
 75     if (maxx!=-1 && minn!=INF && (maxx-minn)>=len)
 76         ++ret;
 77
 78     return ret;
 79 }
 80
 81 void printRank(int n) {
 82     int i;
 83
 84     printf("print rank...\n");
 85     for (i=1; i<=n; ++i)
 86         printf("%d ", rank[i]);
 87     printf("\n");
 88 }
 89
 90 void printHeight(int n) {
 91     int i;
 92
 93     printf("print height...\n");
 94     for (i=1; i<=n; ++i)
 95         printf("%d ", height[i]);
 96     printf("\n");
 97 }
 98
 99 void printSa(int n) {
100     int i;
101
102     printf("print sa...\n");
103     for (i=0; i<=n; ++i)
104         printf("%d ", sa[i]);
105     printf("\n");
106 }
107
108 int main() {
109     int i, len;
110     int ans;
111
112 #ifndef ONLINE_JUDGE
113     freopen("data.in", "r", stdin);
114     freopen("data.out", "w", stdout);
115 #endif
116
117     while (scanf("%s",s)!=EOF && (s[0]!=‘#‘)) {
118         //printf("%s\n", s);
119         for (i=0; s[i]; ++i)
120             str[i] = s[i] - ‘a‘ + 1;
121         str[i] = 0;
122         len = i;
123         da(str, sa, len+1, MAXM);
124         calheight(str, sa, len);
125 #ifndef ONLINE_JUDGE
126         printSa(len);
127         printRank(len);
128         printHeight(len);
129 #endif
130         for (ans=0, i=1; i<=len/2; ++i) {
131             ans += getRepeat(i, len);
132         }
133         printf("%d\n", ans);
134     }
135
136     return 0;
137 }
时间: 2024-10-12 22:41:54

【HDOJ】3518 Boring Counting的相关文章

HDOJ 题目3518 Boring counting(后缀数组,求不重叠重复次数最少为2的子串种类数)

Boring counting Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 2253    Accepted Submission(s): 924 Problem Description 035 now faced a tough problem,his english teacher gives him a string,whic

【HDOJ】P5056 Boring count

题目意思是给你一个字符串和K,让你求其中有多少个字串中每个字母的出现次数不超过K次,可以等于 题目意思是很简单的,写起来也很简单,不过就是注意最后要是long long要不WA了,555~ #include <iostream> #include <cstring> #include <cstdio> using namespace std; char s[100005]; int n,cnt[30],k,T,st; long long ans; int main(){

HDOJ 3518 Boring counting

SAM基本操作 拓扑求每个节点的  最左出现left,最右出现right,出现了几次num ...... 对于每一个出现两次以上的节点,对其所对应的一串子串的长度范围 [fa->len+1,len] 和其最大间距 right-left比较 即可...... Boring counting Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s):

【HDOJ】4956 Poor Hanamichi

基本数学题一道,看错位数,当成大数减做了,而且还把方向看反了.所求为最接近l的值. 1 #include <cstdio> 2 3 int f(__int64 x) { 4 int i, sum; 5 6 i = sum = 0; 7 while (x) { 8 if (i & 1) 9 sum -= x%10; 10 else 11 sum += x%10; 12 ++i; 13 x/=10; 14 } 15 return sum; 16 } 17 18 int main() { 1

【HDOJ】1099 Lottery

题意超难懂,实则一道概率论的题目.求P(n).P(n) = n*(1+1/2+1/3+1/4+...+1/n).结果如果可以除尽则表示为整数,否则表示为假分数. 1 #include <cstdio> 2 #include <cstring> 3 4 #define MAXN 25 5 6 __int64 buf[MAXN]; 7 8 __int64 gcd(__int64 a, __int64 b) { 9 if (b == 0) return a; 10 else return

【HDOJ】2844 Coins

完全背包. 1 #include <stdio.h> 2 #include <string.h> 3 4 int a[105], c[105]; 5 int n, m; 6 int dp[100005]; 7 8 int mymax(int a, int b) { 9 return a>b ? a:b; 10 } 11 12 void CompletePack(int c) { 13 int i; 14 15 for (i=c; i<=m; ++i) 16 dp[i]

【HDOJ】3509 Buge&#39;s Fibonacci Number Problem

快速矩阵幂,系数矩阵由多个二项分布组成.第1列是(0,(a+b)^k)第2列是(0,(a+b)^(k-1),0)第3列是(0,(a+b)^(k-2),0,0)以此类推. 1 /* 3509 */ 2 #include <iostream> 3 #include <string> 4 #include <map> 5 #include <queue> 6 #include <set> 7 #include <stack> 8 #incl

【HDOJ】1818 It&#39;s not a Bug, It&#39;s a Feature!

状态压缩+优先级bfs. 1 /* 1818 */ 2 #include <iostream> 3 #include <queue> 4 #include <cstdio> 5 #include <cstring> 6 #include <cstdlib> 7 #include <algorithm> 8 using namespace std; 9 10 #define MAXM 105 11 12 typedef struct {

【HDOJ】2424 Gary&#39;s Calculator

大数乘法加法,直接java A了. 1 import java.util.Scanner; 2 import java.math.BigInteger; 3 4 public class Main { 5 public static void main(String[] args) { 6 Scanner cin = new Scanner(System.in); 7 int n; 8 int i, j, k, tmp; 9 int top; 10 boolean flag; 11 int t