WC 2009 voice

這題我覺得就是實現和卡常數!!!

不會後綴數組的或者背模板的請先去好好研究後綴數組,至少要有自己的版本,當然,自己的版本至少要經過各大OJ洗禮後才能出爐。

由於不會SpareTable算法,直接zkw線段樹。

還是一樣,將所有串連起來後綴排序,對於每個字,枚舉匹配的位置,O(logn)zkw或O(1)ST的查詢匹配長度,按照查詢結果跳指針,最多K次不匹配,最多跳K次,然後就統計即可。這一步O(nmklogn)zkw或O(nmk)ST

第二問,郭華陽學長的題解有點錯誤,但思想很清晰

記g[i][j]爲從第i位開始以第j個字爲第一個匹配的字的最大匹配數

d[i][j]爲在g[i][j]情況下的方案數

f[i]爲第i位開始的最大匹配數

c[i]爲f[i]情況下的方案數

預處理f[n],c[n],g[n][j],d[n][j]

按照貪心思想,題目只要求本質不同的方案數,所以轉移就很簡單了

做第一問時爲第二問預處理leng[i][j]表示在以i處開始匹配j時的最短長度,ok[i][j]表示以i處開始是否可匹配j

從後往前枚舉i先轉移g,d,再轉移f,c

g[i][j]={

max(g[i+1][j],f[t]+1);ok[i][j]爲true

否則g[i+1][j];

}

d[i][j]={

max(c[t],1);ok[i][j]爲true

否則d[i+1][j];

}

其中t=i+leng[i][j]

f[i]=max(g[i][j]);

c[i]=max(sigma(d[i][j])(g[i][j]==f[i]),1)

#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#define mo 1000003
int a[2100025],count[2100025],ran[2100025],te[2100025],sa[2100025],news[2100025];
int hei[4194309];
int len[25],left[25],right[25];
int n=0,m=0,maink=0,mm=0,maxv=0,ans1=0,ans2=0,totn=0;
int f[100002],c[100002];
int g[100002][21],delta[100002][21],leng[100002][21],d[100002][21];
bool ok[100002][21];
inline int min(int a,int b)
{
  return a<b?a:b;
}
inline int max(int a,int b)
{
  return a>b?a:b;
}
bool cmp(int *s,int a,int b,int l)
{
  return (s[a]==s[b] && s[a+l]==s[b+l]);
}
void doualgo(int *s,int n,int m)
{
  int i=0,l=0,p=1,*rank=ran,*tem=te,*t=NULL;
  memset(count,0,sizeof(count));
  for (i=1;i<=n;i++) count[rank[i]=s[i]]++;
  for (i=1;i<=m;i++) count[i]+=count[i-1];
  for (i=n;i>=1;i--) sa[count[rank[i]]--]=i;
  for (l=1;p<n;m=p,l*=2)
    {
      for (p=0,i=n-l+1;i<=n;i++) tem[++p]=i;
      for (i=1;i<=n;i++) if (sa[i]>l) tem[++p]=sa[i]-l;
      memset(count,0,sizeof(count));
      for (i=1;i<=n;i++) count[news[i]=rank[tem[i]]]++;
      for (i=1;i<=m;i++) count[i]+=count[i-1];
      for (i=n;i>=1;i--) sa[count[news[i]]--]=tem[i];
      for (t=rank,rank=tem,tem=t,t=NULL,rank[sa[0]]=0,p=0,i=1;i<=n;i++)
	rank[sa[i]]=cmp(tem,sa[i],sa[i-1],l)?p:++p;
    }
}
void calhei(int *s,int n)
{
  int i=0,j=0,k=0;
  memset(ran,0,sizeof(ran));
  for (i=1;i<=n;i++) ran[sa[i]]=i;
  for (i=1;i<=n;hei[ran[i++]+mm]=k)
    for (k?k--:k=0,j=sa[ran[i]-1];s[i+k]==s[j+k];k++);
}
void buildzkw()
{
  int i=0;
  for (i=mm-1;i>=1;i--)
    hei[i]=min(hei[i<<1],hei[(i<<1)+1]);
}
int ask(int l,int r)
{
  l=ran[l];
  r=ran[r];
  if (l>r)
    {
      int tmp=l;
      l=r;
      r=tmp;
    }
  l=l+mm;
  r=r+mm+1;
  int o=n+1;
  while (l^r^1)
    {
      if (!(l&1)) o=o>hei[l^1]?hei[l^1]:o;
      if (r&1) o=o>hei[r^1]?hei[r^1]:o;
      l>>=1;
      r>>=1;
    }
  return o;
}
int main()
{
  freopen("voice.in","r",stdin);
  freopen("voice.out","w",stdout);
  scanf("%d%d%d",&n,&m,&maink);
  int i=0,j=0;
  for (i=1;i<=n;i++)
    {
      scanf("%d",&a[i]);
      a[i]++;
      if (a[i]>maxv) maxv=a[i];
    }
  totn=n;
  for (i=1;i<=m;i++)
    {
      scanf("%d",&len[i]);
      left[i]=totn+1;
      for (j=1;j<=len[i];j++)
	{
	  scanf("%d",&a[++totn]);
	  a[totn]++;
	  if (a[totn]>maxv) maxv=a[totn];
	}
      right[i]=totn;
    }
  mm=1<<(int)(log2(totn)+1);
  if (mm<=totn) mm<<=1;
  doualgo(a,totn,maxv);
  calhei(a,totn);
  buildzkw();
  int now=0,pmain=0,ppatt=0,distinc=0,last=0,common=0;
  bool flag=0;
  for (now=1;now<=m;now++)
    {
      flag=0;
      for (i=1;i<=n-len[now]+1;i++)
	{
	  pmain=i,ppatt=left[now];
	  distinc=0;
	  while (distinc<=maink && pmain<=n && ppatt<=right[now])
	    {
	      common=min(min(ask(pmain,ppatt),n-pmain+1),right[now]-ppatt+1);
	      ppatt+=common;
	      pmain+=common+1;
	      distinc++;
	    }
	  if (ppatt>right[now])
	    {
	      flag=1;
	      delta[i][now]=(min(maink-distinc+1,n-pmain+2)+1);
	      ans2+=delta[i][now];
	      leng[i][now]=pmain-i-1;
	      ok[i][now]=1;
	    }
	}
      if (flag) ans1++;
    }
  printf("%d %d\n",ans1,ans2);
  int l=0,t=0;
  for (i=1;i<=m;i++)
    {
      if (ok[n][i])
	{
	  g[n][i]=1;
	  d[n][i]=1;
	  f[n]=1;
	  c[n]++;
	}
    }
  c[n]=max(c[n],1);
  for (i=n-1;i>=1;i--)
    {
      for (j=1;j<=m;j++)
	{
	  if (ok[i][j])
	    {
	      t=i+leng[i][j];
	      g[i][j]=max(g[i+1][j],f[t]+1);
	      d[i][j]=max(c[t],1);
	    }
	  else
	    {
	      d[i][j]=d[i+1][j];
	      g[i][j]=g[i+1][j];
	    }
	  f[i]=max(f[i],g[i][j]);
	}
      for (j=1;j<=m;j++)
	if (f[i]==g[i][j])
	  {
	    c[i]+=d[i][j];
	    if (c[i]>mo) c[i]-=mo;
	  }
      c[i]=max(c[i],1);
    }
  printf("%d %d\n",f[1],c[1]);
  return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章