1. 程式人生 > >BZOJ3620: 似乎在夢中見過的樣子 解題報告

BZOJ3620: 似乎在夢中見過的樣子 解題報告

這題一直沒想出來,後來發現O(n2)能過…….

SA+n2列舉
列舉一個左端點i,處理一下字首i和每個字首的height值,然後往右列舉右端點j,判一下height值是不是>k,如果是的話,把不覆蓋中間全部區間的所有方案加入答案,注意不同j的答案可能重複,所以把能成為答案的j的區間存到一個數組裡,弄一下字首和,掃完j掃一遍陣列就好了(其實好像可以直接一個一個判不用這樣)

code:

#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<ctime> #include<cmath> #include<bitset> #include<string> #include<vector> #include<cstdio> #include<cstdlib> #include<cstring> #include<climits> #include<complex> #include<iostream> #include<algorithm> #define ll long long
using namespace std; const int maxn = 15100; const int maxl = 15; int sa[maxn],rank[maxn],t[maxn],height[maxn]; int fir[maxn],sec[maxn]; int n; void sort_(int *ret,int *rk,int *str,int n,int m) { for(int i=0;i<=m;i++)t[i]=0; for(int i=1;i<=n;i++)t[str[rk[i]]]++; for(int i=1;i<=m;i++)t[i]+=t[i-1
]; for(int i=n;i>=1;i--)ret[t[str[rk[i]]]--]=rk[i]; } int str[maxn]; void get_sa(int n,int m) { for(int i=1;i<=n;i++)rank[i]=i; sort_(sa,rank,str,n,m); rank[sa[1]]=1; for(int i=2;i<=n;i++) rank[sa[i]]=rank[sa[i-1]]+(str[sa[i]]!=str[sa[i-1]]); int cnt=rank[sa[n]],p=1; while(cnt!=n) { for(int i=1;i<=n;i++) { sa[i]=i; fir[i]=rank[i]; sec[i]=i+p>n?0:rank[i+p]; } sort_(rank,sa,sec,n,n); sort_(sa,rank,fir,n,n); rank[sa[1]]=1; for(int i=2;i<=n;i++) rank[sa[i]]=rank[sa[i-1]]+ (fir[sa[i]]!=fir[sa[i-1]]||sec[sa[i]]!=sec[sa[i-1]]); cnt=rank[sa[n]];p<<=1; } } void get_height() { height[1]=0; int k=0; for(int i=1;i<=n;i++) { if(k)k--; if(rank[i]==1)continue; while(str[i+k]==str[sa[rank[i]-1]+k])k++; height[rank[i]]=k; } } char st[maxn]; int kn; int R[maxl][maxn],L[maxn],s[maxn]; int main() { scanf("%s",st); n=strlen(st); scanf("%d",&kn); for(int i=1;i<=n;i++)str[i]=st[i-1]-'a'+1; get_sa(n,28); get_height(); /* for(int i=1;i<=n;i++)R[0][i]=height[i]; for(int i=1;i<maxl;i++) { int kl=1<<(i-1); for(int j=1;j-1+(1<<i)<=n;j++) R[i][j]=min(R[i-1][j],R[i-1][j+kl]); } for(int )*/ ll ans=0; for(int i=1;i<=n;i++) { int l=0; int tt=rank[i],hi=height[tt]; for(int j=tt-1;j>=1;j--) { L[sa[j]]=hi; if(height[j]<hi)hi=height[j]; } hi=height[tt+1]; for(int j=tt+1;j<=n;j++) { if(height[j]<hi)hi=height[j]; L[sa[j]]=hi; } for(int j=i+2;j<=n;j++) { if(L[j]>=kn) { int tmp=L[j]; if(i+tmp-1>=j-1)tmp=j-1-i; s[j+kn-1]++;s[j+tmp]--; } } int ts=0; for(int j=i+2;j<=n;j++) { ts+=s[j]; s[j]=0; if(ts>0)ans++; } } printf("%lld\n",ans); return 0; }