2016 China-Final-F题 ——(SA+二分)

  其实是一个很经典的字符串问题,但是我们比赛的时候没出。

  先看一下UVA11107这题,题意是,找出最长的一个字符串,在至少一半的字符串中出现过。只要把所有的字符串用不同的分隔符分开,然后SA一下,最后二分长度,用height将字符串分组,判断是否超过一半即可。要注意的是,因为分隔符单单用个char已经不够了,所以全部char都换成int,然后用不同的整数来作为分隔符即可。

  代码如下:

  1 #include <stdio.h>
  2 #include <algorithm>
  3 #include <string.h>
  4 #include <vector>
  5 using namespace std;
  6 const int N = 100000 + 1000;
  7 typedef long long ll;
  8 const int sep = 'z' + 1;
  9 
 10 /**
 11  *    sa[i]:表示排在第i位的后缀的起始下标
 12  *    rank[i]:表示后缀suffix(i)排在第几
 13  *    height[i]:sa[i-1] 与 sa[i]的LCP(最长公共前缀)值
 14  *
 15  * */
 16  /*
 17     如果整数的话模板改成int.
 18     加一个数a[n] = 0 。 这样他的排名是第一个。
 19     construct(a,n+1);
 20 
 21     字符串的话。
 22     len = strlen(str);
 23     construct(s,strlen(s)+1);
 24     排名第0的是个空字符串。
 25 
 26     height[i]:sa[i-1] 与 sa[i]的LCP(最长公共前缀)值
 27     所以height[1] = 0;
 28     rank[len] = 0;
 29     sa[0] = len;
 30  */
 31 int sa[N],rnk[N],height[N];
 32 void construct(const int *s,int n,int m = 256) {
 33     static int t1[N],t2[N],c[N];
 34     int *x = t1,*y = t2;
 35     int i,j,k,p,l;
 36     for (i = 0; i < m; ++ i) c[i] = 0;
 37     for (i = 0; i < n; ++ i) c[x[i] = s[i]] ++;
 38     for (i = 1; i < m; ++ i) c[i] += c[i - 1];
 39     for (i = n - 1; i >= 0; -- i) sa[--c[x[i]]] = i;
 40     for (k = 1; k <= n; k <<= 1) {
 41         p = 0;
 42         for (i = n - k; i < n; ++ i) y[p++] = i;
 43         for (i = 0; i < n; ++ i) if (sa[i] >= k) y[p++] = sa[i] - k;
 44         for (i = 0; i < m; ++ i) c[i] = 0;
 45         for (i = 0; i < n; ++ i) c[x[y[i]]] ++;
 46         for (i = 1; i < m; ++ i) c[i] += c[i - 1];
 47         for (i = n - 1; i >= 0; -- i) sa[--c[x[y[i]]]] = y[i];
 48         std::swap(x,y);
 49         p = 1; x[sa[0]] = 0;
 50         for (i = 1; i < n; ++ i)
 51             x[sa[i]] = y[sa[i - 1]] == y[sa[i]]
 52                 && y[sa[i - 1] + k] == y[sa[i] + k] ? p - 1: p ++;
 53         if (p >= n) break;
 54         m = p;
 55     }
 56     for (i = 0; i < n; ++ i) rnk[sa[i]] = i;
 57     for (i = 0,l = 0; i < n; ++ i) {
 58         if (rnk[i]) {
 59             j = sa[rnk[i] - 1];
 60             while (s[i + l] == s[j + l]) l++;
 61             height[rnk[i]] = l;
 62             if (l) l--;
 63         }
 64     }
 65 }
 66 
 67 char str[1005];
 68 int s[N];
 69 int End[105],len,n;
 70 bool vis[105];
 71 vector<int> ans;
 72 
 73 bool solve(int Len)
 74 {
 75     ans.clear();
 76     int cnt = 0;
 77     memset(vis,false,sizeof(vis));
 78     for(int i=2;i<=len;i++)
 79     {
 80         if(height[i] >= Len)
 81         {
 82             for(int j=1;j<=n;j++)
 83             {
 84                 if(sa[i] > End[j-1] && sa[i] < End[j]) {cnt += !vis[j]; vis[j] = 1;}
 85                 if(sa[i-1] > End[j-1] && sa[i-1] < End[j]) {cnt += !vis[j]; vis[j] = 1;}
 86             }
 87         }
 88         else
 89         {
 90             if(cnt > n / 2) ans.push_back(sa[i-1]);
 91             cnt = 0;
 92             memset(vis,false,sizeof(vis));
 93         }
 94     }
 95     if(cnt > n / 2) ans.push_back(sa[len]);
 96     return ans.size();
 97 }
 98 
 99 int main()
100 {
101     int first = 0;
102     while(scanf("%d",&n) == 1 && n)
103     {
104         if(first == 0) first = 1;
105         else puts("");
106         len = 0;
107         for(int i=1;i<=n;i++)
108         {
109             scanf("%s",str);
110             for(int j=0;str[j];j++) s[len++] = str[j];
111 
112             s[len++] = sep + i;
113             End[i] = len-1;
114         }
115         s[len] = 0;
116         construct(s,len+1);
117         int l = 1, r = len, Ans = -1;
118         while(l <= r)
119         {
120             int mid = l + r >> 1;
121             if(solve(mid)) l = mid + 1, Ans = mid;
122             else r = mid - 1;
123         }
124 
125         if(Ans == -1) puts("?");
126         else
127         {
128             // 为了得到答案,再solve一遍
129             solve(Ans);
130             for(int i=0;i<ans.size();i++)
131             {
132                 for(int j=ans[i],cnt=1;cnt<=Ans;j++,cnt++) putchar(s[j]);
133                 puts("");
134             }
135             //puts("");
136         }
137     }
138     return 0;
139 }
View Code

 

  然后看下F题,题意是,找出最短的一个字符串,只在第一个字符串中出现。那么,一样的套路:全部连接,然后SA一遍,然后分组,找这一组中是不是都只是在第一个字符串中出现(这里采用了一个belong数组来判断每个字符是属于哪个串中的)。

  代码如下:

  1 #include <stdio.h>
  2 #include <algorithm>
  3 #include <string.h>
  4 #include <vector>
  5 using namespace std;
  6 const int N = 3e6+7;
  7 const int M = 5e4+7;
  8 typedef long long ll;
  9 const int sep = 'z' + 1;
 10 
 11 /**
 12  *    sa[i]:表示排在第i位的后缀的起始下标
 13  *    rank[i]:表示后缀suffix(i)排在第几
 14  *    height[i]:sa[i-1] 与 sa[i]的LCP(最长公共前缀)值
 15  *
 16  * */
 17  /*
 18     如果整数的话模板改成int.
 19     加一个数a[n] = 0 。 这样他的排名是第一个。
 20     construct(a,n+1);
 21 
 22     字符串的话。
 23     len = strlen(str);
 24     construct(s,strlen(s)+1);
 25     排名第0的是个空字符串。
 26 
 27     height[i]:sa[i-1] 与 sa[i]的LCP(最长公共前缀)值
 28     所以height[1] = 0;
 29     rank[len] = 0;
 30     sa[0] = len;
 31  */
 32 int sa[N],rnk[N],height[N];
 33 void construct(const int *s,int n,int m = 256) {
 34     static int t1[N],t2[N],c[N];
 35     int *x = t1,*y = t2;
 36     int i,j,k,p,l;
 37     for (i = 0; i < m; ++ i) c[i] = 0;
 38     for (i = 0; i < n; ++ i) c[x[i] = s[i]] ++;
 39     for (i = 1; i < m; ++ i) c[i] += c[i - 1];
 40     for (i = n - 1; i >= 0; -- i) sa[--c[x[i]]] = i;
 41     for (k = 1; k <= n; k <<= 1) {
 42         p = 0;
 43         for (i = n - k; i < n; ++ i) y[p++] = i;
 44         for (i = 0; i < n; ++ i) if (sa[i] >= k) y[p++] = sa[i] - k;
 45         for (i = 0; i < m; ++ i) c[i] = 0;
 46         for (i = 0; i < n; ++ i) c[x[y[i]]] ++;
 47         for (i = 1; i < m; ++ i) c[i] += c[i - 1];
 48         for (i = n - 1; i >= 0; -- i) sa[--c[x[y[i]]]] = y[i];
 49         std::swap(x,y);
 50         p = 1; x[sa[0]] = 0;
 51         for (i = 1; i < n; ++ i)
 52             x[sa[i]] = y[sa[i - 1]] == y[sa[i]]
 53                 && y[sa[i - 1] + k] == y[sa[i] + k] ? p - 1: p ++;
 54         if (p >= n) break;
 55         m = p;
 56     }
 57     for (i = 0; i < n; ++ i) rnk[sa[i]] = i;
 58     for (i = 0,l = 0; i < n; ++ i) {
 59         if (rnk[i]) {
 60             j = sa[rnk[i] - 1];
 61             while (s[i + l] == s[j + l]) l++;
 62             height[rnk[i]] = l;
 63             if (l) l--;
 64         }
 65     }
 66 }
 67 
 68 char str[N];
 69 int s[N];
 70 int endlen[N],len,n,belong[N];
 71 char temp[N];
 72 int all;
 73 int from;
 74 
 75 bool check(int st,int ed,int L)
 76 {
 77     int now = -1;
 78     for(int i=st;i<=ed;i++)
 79     {
 80         if(belong[sa[i]] == 1 && endlen[sa[i]] >= L)
 81         {
 82             if(now == -1) now = sa[i];
 83             continue;
 84         }
 85         return false;
 86     }
 87     from = now;
 88     return true;
 89 }
 90 
 91 bool solve(int L)
 92 {
 93     int st = 1, ed = 1;
 94     for(int i=2;i<all;i++)
 95     {
 96         if(height[i] >= L) ed++;
 97         else
 98         {
 99             if(check(st,ed,L)) return 1;
100             st = ed = i;
101         }
102     }
103     return check(st,ed,L);
104 }
105 
106 int main()
107 {
108     int T, kase = 1;
109     scanf("%d",&T);
110     while(T--)
111     {
112         printf("Case #%d: ",kase++);
113         scanf("%d%s",&n,temp);
114         int now_len = strlen(temp);
115         len = 0;
116         for(int i=0;temp[i];i++)
117         {
118             s[len] = temp[i];
119             belong[len] = 1;
120             endlen[len] = now_len - i;
121             len ++;
122         }
123         s[len] = sep + 1; belong[len] = 1, endlen[len] = 0;
124         int first_len = len ++;
125         for(int i=2;i<=n;i++)
126         {
127             scanf("%s",str);
128             int now_len = strlen(str);
129             for(int j=0;j<now_len;j++)
130             {
131                 s[len] = str[j];
132                 belong[len] = i;
133                 endlen[len] = now_len - j;
134                 len ++;
135             }
136             s[len] = sep + i; belong[len] = i, endlen[len] = 0; len++;
137         }
138         s[len] = 0;
139         construct(s,len+1,50000 + 500);
140         all = rnk[first_len];
141         int l = 0, r = first_len, ans = -1;
142         while(l <= r)
143         {
144             int mid = l + r >> 1;
145             if(solve(mid)) r = mid - 1, ans = mid;
146             else l = mid + 1;
147         }
148         if(ans == -1) puts("Impossible");
149         else
150         {
151             for(int i=from;i<from+ans;i++) printf("%c",temp[i]);
152             puts("");
153         }
154     }
155     return 0;
156 }
View Code

 

  感觉二分+SA就是一种套路,可以结合前几天做的那题一起看看,最少出现m次的最长字符串。

转载于:https://www.cnblogs.com/zzyDS/p/6207169.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值