zoukankan      html  css  js  c++  java
  • BZOJ3019 : [Balkan2012]handsome

    首先预处理出$f[i][j][k]$表示长度为$i$的序列,第一个位置是$j$,最后一个位置是$k$时合法的方案数。

    从后往前枚举LCP以及那个位置应该改成什么。

    用线段树维护区间内最左最右的已经确定的位置,以及区间内的合法方案数。

    合并的时候只需要将左右儿子的答案乘起来,然后再乘以左儿子最右到右儿子最左这一段区间的方案数即可。

    时间复杂度$O(nlog n)$。

    #include<cstdio>
    const int N=400010,M=1050000,P=1000000007;
    int n,m,i,j,k,x,a[N],g[3][3],f[N][3][3],pos[N],v[N],l[M],r[M],val[M],ans=1;char ch[9],s[N];
    inline void read(int&a){char c;while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';}
    inline void up(int&x,int y){x+=y;if(x>=P)x-=P;}
    void build(int x,int a,int b){
      l[x]=a,r[x]=b,val[x]=1;
      if(a==b){pos[a]=x;return;}
      int mid=(a+b)>>1;
      build(x<<1,a,mid),build(x<<1|1,mid+1,b);
    }
    inline bool change(int x,int p){
      if(~p){
        if(x>1&&~v[x-1])if(g[v[x-1]][p])return 0;
        if(x<n&&~v[x+1])if(g[p][v[x+1]])return 0;
      }
      v[x]=p,x=pos[x];
      if(p<0)l[x]=r[x]=0;
      for(x>>=1;x;x>>=1){
        l[x]=l[x<<1]?l[x<<1]:l[x<<1|1];
        r[x]=r[x<<1|1]?r[x<<1|1]:r[x<<1];
        val[x]=1LL*val[x<<1]*val[x<<1|1]%P;
        if(r[x<<1]&&l[x<<1|1])val[x]=1LL*val[x]*f[l[x<<1|1]-r[x<<1]+1][v[r[x<<1]]][v[l[x<<1|1]]]%P;
      }
      return 1;
    }
    inline int ask(){
      int ret=val[1],t,i;
      if(l[1]>1){
        for(t=i=0;i<3;i++)up(t,f[l[1]][i][v[l[1]]]);
        ret=1LL*ret*t%P;
      }
      if(r[1]<n){
        for(t=i=0;i<3;i++)up(t,f[n-r[1]+1][v[r[1]]][i]);
        ret=1LL*ret*t%P;
      }
      return ret;
    }
    int main(){
      read(n);
      for(i=1;i<=n;i++)read(a[i]);
      read(m);
      while(m--)scanf("%s",ch),g[ch[0]-'1'][ch[1]-'1']=1;
      scanf("%s",s+1);
      for(i=1;i<=n;i++)s[i]-='1',v[i]=s[i];
      for(i=0;i<3;i++)f[1][i][i]=1;
      for(i=1;i<n;i++)for(j=0;j<3;j++)for(k=0;k<3;k++)if(f[i][j][k])for(x=0;x<3;x++)if(!g[k][x])up(f[i+1][j][x],f[i][j][k]);
      build(1,1,n);
      for(i=n;i;change(a[i--],-1))for(j=0;j<s[a[i]];j++)if(change(a[i],j))up(ans,ask());
      return printf("%d",ans),0;
    }
    

      

  • 相关阅读:
    HDU 4472 Count DP题
    HDU 1878 欧拉回路 图论
    CSUST 1503 ZZ买衣服
    HDU 2085 核反应堆
    HDU 1029 Ignatius and the Princess IV
    UVa 11462 Age Sort
    UVa 11384
    UVa 11210
    LA 3401
    解决学一会儿累了的问题
  • 原文地址:https://www.cnblogs.com/clrs97/p/6371367.html
Copyright © 2011-2022 走看看