bzoj 4278: [ONTAK2015]Tasowanie&bzoj 1692: [Usaco2007 Dec]队列变换 后缀数组+贪心
2017-05-28 11:30
417 查看
题意
给定两个数字串A和B,通过将A和B进行二路归并得到一个新的数字串T,请找到字典序最小的T。1<=n,m<=200000,1<=A[i],B[i]<=1000分析
先把两个串放一起求sa,然后用两个指针维护两个串分别归并到哪一位,每次选字典序较大的即可。证明看这里
代码
bzoj 4278#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; const int N=400005; int n,m,s1 ,s2 ,rank[N*2],sa ,b ,d ,c ,s ; void get_sa(int n,int m) { for (int i=1;i<=n;i++) b[s[i]]++; for (int i=1;i<=m;i++) b[i]+=b[i-1]; for (int i=n;i>=1;i--) c[b[s[i]]--]=i; int t=0; for (int i=1;i<=n;i++) { if (s[c[i]]!=s[c[i-1]]) t++; rank[c[i]]=t; } int j=1; while (j<=n) { for (int i=1;i<=n;i++) b[i]=0; for (int i=1;i<=n;i++) b[rank[i+j]]++; for (int i=1;i<=n;i++) b[i]+=b[i-1]; for (int i=n;i>=1;i--) c[b[rank[i+j]]--]=i; for (int i=1;i<=n;i++) b[i]=0; for (int i=1;i<=n;i++) b[rank[i]]++; for (int i=1;i<=n;i++) b[i]+=b[i-1]; for (int i=n;i>=1;i--) d[b[rank[c[i]]]--]=c[i]; t=0; for (int i=1;i<=n;i++) { if (rank[d[i]]!=rank[d[i-1]]||rank[d[i]]==rank[d[i-1]]&&rank[d[i]+j]!=rank[d[i-1]+j]) t++; c[d[i]]=t; } for (int i=1;i<=n;i++) rank[i]=c[i]; if (t==n) break; j*=2; } for (int i=1;i<=n;i++) sa[rank[i]]=i; } int main() { scanf("%d",&n); for (int i=1;i<=n;i++) scanf("%d",&s1[i]); scanf("%d",&m); for (int i=1;i<=m;i++) scanf("%d",&s2[i]); for (int i=1;i<=n;i++) s[i]=s1[i]; s[n+1]=10000; for (int i=1;i<=m;i++) s[i+n+1]=s2[i]; get_sa(n+m+1,10000); int p=1,q=1; while (p<=n||q<=m) if (p<=n&&rank[p]<=rank[q+n+1]||q>m) printf("%d ",s1[p]),p++; else printf("%d ",s2[q]),q++; return 0; }
bzoj 1692
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; const int N=60005; int n,m,rank[N*2],sa ,b ,d ,c ; char s ,s1 ; void get_sa(int n,int m) { for (int i=1;i<=n;i++) b[s[i]]++; for (int i=1;i<=m;i++) b[i]+=b[i-1]; for (int i=n;i>=1;i--) c[b[s[i]]--]=i; int t=0; for (int i=1;i<=n;i++) { if (s[c[i]]!=s[c[i-1]]) t++; rank[c[i]]=t; } int j=1; while (j<=n) { for (int i=1;i<=n;i++) b[i]=0; for (int i=1;i<=n;i++) b[rank[i+j]]++; for (int i=1;i<=n;i++) b[i]+=b[i-1]; for (int i=n;i>=1;i--) c[b[rank[i+j]]--]=i; for (int i=1;i<=n;i++) b[i]=0; for (int i=1;i<=n;i++) b[rank[i]]++; for (int i=1;i<=n;i++) b[i]+=b[i-1]; for (int i=n;i>=1;i--) d[b[rank[c[i]]]--]=c[i]; t=0; for (int i=1;i<=n;i++) { if (rank[d[i]]!=rank[d[i-1]]||rank[d[i]]==rank[d[i-1]]&&rank[d[i]+j]!=rank[d[i-1]+j]) t++; c[d[i]]=t; } for (int i=1;i<=n;i++) rank[i]=c[i]; if (t==n) break; j*=2; } for (int i=1;i<=n;i++) sa[rank[i]]=i; } int main() { scanf("%d",&n); for (int i=1;i<=n;i++) scanf("%s",s1+i); for (int i=1;i<=n;i++) s[i]=s1[i]; s[n+1]='&'; for (int i=1;i<=n;i++) s[i+n+1]=s1[n-i+1]; get_sa(n*2+1,10000); int p=1,q=n,tot=0; while (p<=q) { if (rank[p]<=rank[n+1+n-q+1]) putchar(s1[p]),p++; else putchar(s1[q]),q--; tot=(tot+1)%80; if (!tot) putchar('\n'); } return 0; }
相关文章推荐
- bzoj4278[ONTAK2015]Tasowanie & bzoj1692[USACO 2007Dec]队列变换(Best Cow Line) 贪心正确性证明
- 【BZOJ】1692 & 1640: [Usaco2007 Dec]队列变换(后缀数组+贪心)
- 【BZOJ1692】[Usaco2007 Dec]队列变换【后缀数组】【贪心】
- [BZOJ 1692] [Usaco2007 Dec] 队列变换 【后缀数组 + 贪心】
- bzoj 1640 && bzoj 1692: [Usaco2007 Dec]队列变换(后缀数组)
- BZOJ 1692: [Usaco2007 Dec]队列变换 [后缀数组 贪心]
- bzoj1692 [Usaco2007 Dec]队列变换 后缀数组+贪心
- 【BZOJ1692】[Usaco2007 Dec]队列变换 后缀数组+贪心
- 1692: [Usaco2007 Dec]队列变换 后缀数组+贪心
- bzoj1692 [Usaco2007 Dec]队列变换(后缀数组)
- 1692: [Usaco2007 Dec]队列变换|后缀数组|贪心
- bzoj 1640||1692: [Usaco2007 Dec]队列变换【后缀数组】
- BZOJ_1692_[Usaco2007 Dec]队列变换_后缀数组
- 1692: [Usaco2007 Dec]队列变换|后缀数组|贪心
- BZOJ 1692 [Usaco2007 Dec]队列变换 暴力(正解后缀数组)
- [BZOJ1692][Usaco2007 Dec]队列变换(贪心+后缀数组)
- [bzoj1692][Usaco2007 Dec]队列变换——贪心+后缀数组
- [后缀数组 贪心] BZOJ 4278 [ONTAK2015]Tasowanie
- BZOJ 1692: [Usaco2007 Dec]队列变换( 贪心 )
- bzoj:1692 [Usaco2007 Dec]队列变换&&1640 [Usaco2007 Nov]Best Cow Line 队列变换