zoukankan      html  css  js  c++  java
  • NOIP2000TG T2 乘积最大

    题目链接

    题意:

     将$N(6<=N<=40)$位的数字,用$K(1<=K<=6)$个乘号隔开,求最大积。

     

    程序1(0pt):

    看到分割/合并,考虑区间DP,思考一下,因为区间个数有限制,不能套区间DP乱搞。

    因为乘法满足结合律,考虑将“摸到第$i$位”和“在这一位后放置第$j$个乘号”作为两个维度进行DP,记录最大值,设为$f_{i,j}$。

    首先设给定数串为$a$,取其一部分的函数为$cut(a,l,r)$,发现从高位和低位开始取是一样的,为了简化,就和高精度一样,以最低位为第$1$位。

    每次用第一个乘号时产生初值,每次从$j-1$的状态里转移。

    同时,因为只能从计算过的状态转移才有意义,并且为了避免做高精乘法的时候出现不可知的奇怪错误,所以考虑在实现DP的时候维护这个访问值,设为$v$。

    考虑寻找上一个节点的位数$p$满足

    ①$p>=j-1$,因为这里要放置第$j-1$个乘号,至少为第$j-1$位

    ②$p<i$,从前往后转移

    ③$f_{p,j-1}必须被访问过$

    于是我们有

    $$f_{i,j}=mathop{max}limits_{p=j-1}^{i-1}{([v_{p,j-1}]*f_{p,j-1}*cut(a,p+1,i)}$$

    跑完$f_{i}$之后,显然$f_{i,k}$就是答案候选了。

    然而有一个问题,就是读入。遇到这种数字和字串混合的输入很容易被爆。第一次提交的时候就因为读入爆〇了。好尴尬啊。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    typedef long long LL;
    const int N=40;
    const int M=6;
    
    struct num{
        int s[N+3],l;
        
        num(int x){
            memset(s,0,sizeof s);
            
            if(x==0){
                l=1;
                return ;
                
            }
            
            l=0;
            while(x>0){
                s[++l]=x%10;
                x/=10;
                
            }
            
        }
        
        num(){}
        
        int operator[](int i){
            return s[i];
            
        }
        
    };
    
    void prt(num a){
        for(int i=a.l;i>=1;i--)
            putchar(a[i]+'0');
        
    }
    
    num operator*(num a,num b){
        num c=num(0);
        
        for(int i=1;i<=a.l;i++)
            for(int j=1;j<=b.l;j++)
                c.s[i+j-1]+=a[i]*b[j];
        
        c.l=a.l+b.l+1;
        for(int i=1;i<c.l;i++){
            c.s[i+1]+=c[i]/10;
            c.s[i]%=10;
            
        }
        while(c[c.l]==0)
            c.l--;
            
        return c;
        
    }
    
    bool operator<(num a,num b){
        if(a.l!=b.l)
            return a.l<b.l;
        
        for(int i=a.l;i>=1;i--)
            if(a[i]!=b[i])
                return a[i]<b[i];
        return false;
        
    }
    
    num max(num a,num b){
        if(a<b)
            return b;
        return a;
        
    }
    
    num cut(num a,int l,int r){
        num b(0);    b.l=r-l+1;
        for(int i=1;i<=b.l;i++)
            b.s[i]=a[l+i-1];
        return b;
        
    }
    
        num a;
        int n,k;
        num f[N+3][M+3],ans[N+3];
        bool v[N+3][M+3];
        
    
    int main(){
        scanf("%d%d",&n,&k);getchar();
        char ch;    a.l=n;
        for(int i=n;i>=1;i--){
            ch=getchar();
            a.s[i]=ch-'0';
            
        }
        
        memset(v,0,sizeof 0);
        for(int i=1;i<n;i++){            
            f[i][1]=cut(a,1,i);
            v[i][1]=true;
            
            for(int j=2;j<=k;j++)        
                for(int p=j-1;p<i;p++)    
                if(v[p][j-1]){
                    v[i][j]=1;
                    f[i][j]=max(f[i][j]
                        ,f[p][j-1]*cut(a,p+1,i));
                    
                }
                
            if(v[i][k])    
                ans[i]=f[i][k]*cut(a,i+1,n);
        
        num maxa(0);
        for(int i=1;i<n;i++)
        if(v[i][k])
            maxa=max(maxa,ans[i]);
        prt(maxa);
        
        return 0;
        
    }

    程序2(100pt):

    思考了一下,应该是$scanf$和$getchar$混在同一行,那个回车不知何去何从导致的。其实我现在还没太搞明白个中机制。

    考虑用模式串把回车收起来。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    typedef long long LL;
    const int N=40;
    const int M=6;
    
    struct num{
        int s[N+3],l;
        
        num(int x){
            memset(s,0,sizeof s);
            
            if(x==0){
                l=1;
                return ;
                
            }
            
            l=0;
            while(x>0){
                s[++l]=x%10;
                x/=10;
                
            }
            
        }
        
        num(){}
        
        int operator[](int i){
            return s[i];
            
        }
        
    };
    
    void prt(num a){
        for(int i=a.l;i>=1;i--)
            putchar(a[i]+'0');
        
    }
    
    num operator*(num a,num b){
        num c=num(0);
        
        for(int i=1;i<=a.l;i++)
            for(int j=1;j<=b.l;j++)
                c.s[i+j-1]+=a[i]*b[j];
        
        c.l=a.l+b.l+1;
        for(int i=1;i<c.l;i++){
            c.s[i+1]+=c[i]/10;
            c.s[i]%=10;
            
        }
        while(c[c.l]==0)
            c.l--;
            
        return c;
        
    }
    
    bool operator<(num a,num b){
        if(a.l!=b.l)
            return a.l<b.l;
        
        for(int i=a.l;i>=1;i--)
            if(a[i]!=b[i])
                return a[i]<b[i];
        return false;
        
    }
    
    num max(num a,num b){
        if(a<b)
            return b;
        return a;
        
    }
    
    num cut(num a,int l,int r){
        num b(0);    b.l=r-l+1;
        for(int i=1;i<=b.l;i++)
            b.s[i]=a[l+i-1];
        return b;
        
    }
    
        num a;
        int n,k;
        num f[N+3][M+3],ans[N+3];
        bool v[N+3][M+3];
        
    
    int main(){
        scanf("%d%d
    ",&n,&k);
        char ch;    a.l=n;
        for(int i=n;i>=1;i--){
            ch=getchar();
            a.s[i]=ch-'0';
            
        }
        
        memset(v,0,sizeof 0);
        for(int i=1;i<n;i++){                
            f[i][1]=cut(a,1,i);
            v[i][1]=true;
            
            for(int j=2;j<=k;j++)                
                for(int p=j-1;p<i;p++)                
                if(v[p][j-1]){
                    v[i][j]=1;
                    f[i][j]=max(f[i][j]
                        ,f[p][j-1]*cut(a,p+1,i));
                    
                }
                
            if(v[i][k])                        
                ans[i]=f[i][k]*cut(a,i+1,n);        
        
        num maxa(0);
        for(int i=1;i<n;i++)
        if(v[i][k])
            maxa=max(maxa,ans[i]);
        prt(maxa);
        
        return 0;
        
    }

    小结:

    要命的字符串搞法……

  • 相关阅读:
    ANSI C
    如何判断机器的endianness
    union的常见用法
    主流浏览器引擎
    用宏来求数组元素个数
    inode
    分区时"磁盘上没有足够的空间完成此操作"的解决方法
    删除OEM分区
    jquery加table布局 模仿实现FaceBook Dialog
    Container.DataItem使用
  • 原文地址:https://www.cnblogs.com/Hansue/p/10960815.html
Copyright © 2011-2022 走看看