BZOJ3620: 似乎在夢中見過的樣子 解題報告
阿新 • • 發佈:2019-01-10
這題一直沒想出來,後來發現
列舉一個左端點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;
}