zoukankan      html  css  js  c++  java
  • BZOJ1386 : [Baltic2000]Stickers

    显然每一位的限制独立,对于每一位求出仅限制该位下的最大数,然后求最小值即可。

    假设当前要求数字$d$的答案:

    考虑填数字的过程,可以看作依次考虑一个序列中的每个数,当前缀和$<0$时退出。

    设$dp[i][j][k]$表示正在考虑最低的$i$位,高位部分有$j$个$d$,第$i$位能不能填$0$为$k$时,所有可能的数字形成的序列的信息。

    这个信息需要维护两个值:

    • $f$:前缀和最小值。
    • $s$:总和。

    显然这个信息可以进行合并。

    求出答案的位数后,再从高到低逐位确定即可。

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

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int N=100,B=10000,MAXL=25;
    int cur,v[N][N][2];
    struct Num{
      int a[MAXL],len,fu;
      Num(){len=1,fu=a[1]=0;}
      void clr(){len=1,fu=a[1]=0;}
      Num operator+(const Num&b)const{
        Num c;
        c.len=max(len,b.len)+2;
        int i;
        for(i=1;i<=c.len;i++)c.a[i]=0;
        if(fu==b.fu){
          for(i=1;i<=len;i++)c.a[i]=a[i];
          for(i=1;i<=b.len;i++)c.a[i]+=b.a[i];
          for(i=1;i<=c.len;i++)if(c.a[i]>=B)c.a[i+1]++,c.a[i]-=B;
          while(c.len>1&&!c.a[c.len])c.len--;
          c.fu=fu;
        }else{
          bool flag=0;
          if(len==b.len){
            for(i=len;i;i--)if(a[i]!=b.a[i]){
              if(a[i]>b.a[i])flag=1;
              break;
            }
          }else{
            if(len>b.len)flag=1;
          }
          if(flag){
            for(i=1;i<=len;i++)c.a[i]=a[i];
            for(i=1;i<=b.len;i++)c.a[i]-=b.a[i];
            for(i=1;i<=c.len;i++)if(c.a[i]<0)c.a[i+1]--,c.a[i]+=B;
            while(c.len>1&&!c.a[c.len])c.len--;
            c.fu=fu;
          }else{
            for(i=1;i<=b.len;i++)c.a[i]=b.a[i];
            for(i=1;i<=len;i++)c.a[i]-=a[i];
            for(i=1;i<=c.len;i++)if(c.a[i]<0)c.a[i+1]--,c.a[i]+=B;
            while(c.len>1&&!c.a[c.len])c.len--;
            c.fu=b.fu;
          }
        }
        return c;
      }
      Num operator-(Num b)const{
        b.fu^=1;
        return *this+b;
      }
      Num operator*(const Num&b)const{
        Num c;
        c.len=len+b.len+2;
        c.fu=fu^b.fu;
        int i,j;
        for(i=1;i<=c.len;i++)c.a[i]=0;
        for(i=1;i<=len;i++)for(j=1;j<=b.len;j++){
          c.a[i+j-1]+=a[i]*b.a[j];
          if(c.a[i+j-1]>=B){
            c.a[i+j]+=c.a[i+j-1]/B;c.a[i+j-1]%=B;
            if(c.a[i+j]>=B)c.a[i+j+1]+=c.a[i+j]/B,c.a[i+j]%=B;
          }
        }
        while(c.len>1&&!c.a[c.len])c.len--;
        return c;
      }
      bool iszero()const{
        return len==1&&!a[1];
      }
      void write(){
        if(len==1&&!a[1])fu=0;
        if(fu)putchar('-');
        printf("%d",a[len]);
        for(int i=len-1;i;i--)printf("%04d",a[i]);
      }
      void set(int x){
        if(x<0)fu=1,x=-x;else fu=0;
        if(x>=B){
          len=2;
          a[1]=x%B;
          a[2]=x/B;
        }else{
          len=1;
          a[1]=x;
        }
      }
      int sgn()const{
        if(iszero())return 0;
        return fu==1?-1:1;
      }
      int cmp(const Num&b)const{
        int x=sgn(),y=b.sgn();
        if(x!=y)return x<y?-1:1;
        if(!x)return 0;
        if(x>0){
          if(len!=b.len)return len<b.len?-1:1;
          for(int i=len;i;i--)if(a[i]!=b.a[i])return a[i]<b.a[i]?-1:1;
          return 0;
        }
        if(len!=b.len)return len>b.len?-1:1;
        for(int i=len;i;i--)if(a[i]!=b.a[i])return a[i]>b.a[i]?-1:1;
        return 0;
      }
      bool operator<(const Num&b)const{return cmp(b)<0;}
      bool operator==(const Num&b)const{return cmp(b)==0;}
      bool operator>(const Num&b)const{return cmp(b)>0;}
    }ans,val[11];
    struct P{
      Num f,s;
      P(){f.clr();s.clr();}
      void clr(){f.clr();s.clr();}
      P(Num _f,Num _s){f=_f,s=_s;}
      P operator+(const P&b)const{return P(min(f,s+b.f),s+b.s);}
      void operator+=(const P&b){*this=*this+b;}
    }base,f[N][N][2];
    P dfs(int x,int y,int z){
      if(x==0){
        P t;
        t.f.set(-y);
        t.s.set(-y);
        return base+t;
      }
      if(v[x][y][z]==cur+1)return f[x][y][z];
      v[x][y][z]=cur+1;
      P t;
      t.clr();
      for(int i=z;i<10;i++)t+=dfs(x-1,y+(i==cur),0);
      return f[x][y][z]=t;
    }
    Num solve(int _cur,int _base){
      cur=_cur;
      base.f.set(0);
      base.s.set(_base);
      int i,j,len;
      P pre;
      pre.clr();
      for(len=1;;len++){
        P now=dfs(len,0,1);
        if((pre+now).f.sgn()<0)break;
        pre+=now;
      }
      Num ans=val[0];
      int sum=0;
      for(i=len;i;i--)for(j=i==len?1:0;;j++){
        int nowsum=sum+(j==cur);
        P now=dfs(i-1,nowsum,0);
        if((pre+now).f.sgn()<0){
          sum=nowsum;
          ans=ans*val[10]+val[j];
          break;
        }
        pre+=now;
      }
      return ans;
    }
    int main(){
      for(int i=0;i<11;i++)val[i].set(i);
      for(int i=0;i<10;i++){
        int x;
        scanf("%d",&x);
        if(i==0)ans=solve(i,x);
        else ans=min(ans,solve(i,x));
      }
      ans=ans-val[1];
      ans.write();
      return 0;
    }
    

      

  • 相关阅读:
    PHP笔试题
    找工作的几种方式
    ThinkPHP3.2.3学习笔记5---模板(一)
    PHP7新特性
    了解Web Uploader
    什么是云购网
    使用PDO操作数据库的好处
    MySQL与MongoDB的区别
    显示和编辑注解
    自定义验证逻辑
  • 原文地址:https://www.cnblogs.com/clrs97/p/9989322.html
Copyright © 2011-2022 走看看