zoukankan      html  css  js  c++  java
  • BZOJ3764 : Petya的序列

    首先如果一段连续子序列里没有任何幸运数,那么显然可以缩成一个点。

    设幸运数个数为$m$,那么现在序列长度是$O(m)$的,考虑暴力枚举$R_1$,然后从右往左枚举$L_1$。

    每次碰到一个幸运数,就将它删去,维护出被删的数它左边右边连续能到的位置,然后用组合数计算贡献。

    考虑给每个被删数字一个删除时间$b_i$,那么等价于询问它左边右边第一个$b$小于$b_i$的位置,可以通过两遍单调栈得到。

    时间复杂度$O(m^2)$。

    #include<cstdio>
    #include<algorithm>
    typedef unsigned long long ll;
    const int N=2005,M=100010;
    int n,m,p,lim,i,j,a[N],v[N],s[N],g[M],nxt[N],vis[M];
    int b[N],c[N],cnt,pos[N],ex,L[N],R[N],q[N],t;
    ll f[M],C[M][5],sum[N],ans;
    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 int trans(int x){
      if(x==0)return -1;
      int t=x;
      while(x){
        int y=x%10;
        if(y!=4&&y!=7)return -1;
        x/=10;
      }
      return t;
    }
    inline int lower(int x){
      int l=1,r=n,mid,t;
      while(l<=r)if(b[mid=(l+r)>>1]<=x)l=(t=mid)+1;else r=mid-1;
      return t;
    }
    inline int add(int x,int y){nxt[y]=g[x];g[x]=y;}
    inline void del(int x){
      if(x<0)return;
      if(vis[x])return;
      vis[x]=1;
      for(int i=g[x];i;i=nxt[i])if(i>lim){
        b[i]=++cnt;
        c[cnt]=i;
        if(i<ex)ex=i;
      }
    }
    inline ll cal(int l,int x,int r){return f[s[x-1]-s[l-1]]+f[s[r]-s[x]]-f[s[r]-s[l-1]];}
    int main(){
      read(n);
      for(i=1;i<=n;i++)f[i]=1ULL*i*(i+1)/2ULL;
      for(i=1;i<=n;i++){
        C[i][1]=i;
        if(i<=4)C[i][i]=1;
        for(j=2;j<=4&&j<i;j++)C[i][j]=C[i-1][j-1]+C[i-1][j];
      }
      while(n--){
        read(i);
        i=trans(i);
        if(~i||a[m]>=0)a[++m]=i;else a[m]--;
      }
      for(i=1;i<=m;i++){
        if(a[i]>0)b[++p]=a[i],v[i]=1;else v[i]=-a[i];
        s[i]=s[i-1]+v[i];
      }
      if(p>1)for(std::sort(b+1,b+p+1),n=0,i=1;i<=p;i++)if(b[i]!=b[i-1])b[++n]=b[i];
      for(i=1;i<=m;i++)if(a[i]>0)add(a[i]=lower(a[i]),i);
      for(lim=1;lim<=m;lim++){
        for(cnt=i=0;i<=n;i++)vis[i]=0;
        ex=m+1;
        for(i=lim+1;i<=m;i++)b[i]=N;
        for(i=lim;i;i--){
          del(a[i]);
          pos[i]=cnt;
          if(i<lim){
            ans+=(C[v[lim]][3]+C[v[lim]][2]*(s[ex-1]-s[lim]+1))*v[i];
          }else{
            ans+=C[v[i]][2]+C[v[i]][3]*2ULL+C[v[i]][4];
            ans+=(C[v[i]][2]+C[v[i]][3])*(s[ex-1]-s[lim]);
          }
        }
        for(b[q[t=0]=lim]=0,i=lim+1;i<=m;q[++t]=i++){
          while(b[q[t]]>=b[i])t--;
          L[i]=q[t]+1;
        }
        for(b[q[t=0]=m+1]=0,i=m;i>lim;q[++t]=i--){
          while(b[q[t]]>=b[i])t--;
          R[i]=q[t]-1;
        }
        sum[0]=f[s[m]-s[lim]];
        for(i=1;i<=cnt;i++)sum[i]=sum[i-1]+cal(L[c[i]],c[i],R[c[i]]);
        ans+=sum[pos[lim]]*f[v[lim]];
        for(i=lim-1;i;i--)ans+=sum[pos[i]]*v[i]*v[lim];
      }
      return printf("%llu",ans),0;
    }
    

      

  • 相关阅读:
    android 多线程
    Uva 10881 Piotr’s Ants 蚂蚁
    LA 3708 Graveyard 墓地雕塑 NEERC 2006
    UVa 11300 Spreading the Wealth 分金币
    UVa 11729 Commando War 突击战
    UVa 11292 The Dragon of Loowater 勇者斗恶龙
    HDU 4162 Shape Number
    HDU 1869 六度分离
    HDU 1041 Computer Transformation
    利用可变参数函数清空多个数组
  • 原文地址:https://www.cnblogs.com/clrs97/p/5294041.html
Copyright © 2011-2022 走看看