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

      

  • 相关阅读:
    Ubuntu 16 安装redis客户端
    crontab 参数详解
    PHP模拟登录发送闪存
    Nginx配置端口访问的网站
    Linux 增加对外开放的端口
    Linux 实用指令之查看端口开启情况
    无敌的极路由
    不同的域名可以指向同一个项目
    MISCONF Redis is configured to save RDB snapshots, but is currently not able to persist on disk. Commands that may modify the data set are disabled. Please check Redis logs for details about the error
    Redis 创建多个端口
  • 原文地址:https://www.cnblogs.com/clrs97/p/9989322.html
Copyright © 2011-2022 走看看