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;
    }
    

      

  • 相关阅读:
    20145236 《Java程序设计》 第6周学习总结
    20145236 《Java程序设计》第4周学习总结
    20145236 冯佳 《Java程序设计》第3周学习总结
    20145236 冯佳 《Java程序设计》第2周学习总结
    《Java程序设计》实验三 实验报告
    20145202马超 《Java程序设计》第九周学习总结
    20145202马超 《Java程序设计》第八周学习总结
    20145202马超 实验二《Java面向对象程序设计》实验报告
    20145202马超 《Java程序设计》第七周学习总结
    20145202马超 《Java程序设计》第六周学习总结
  • 原文地址:https://www.cnblogs.com/clrs97/p/5294041.html
Copyright © 2011-2022 走看看