Luogu - P1018 乘積最大 - 題解

原文:https://www.luogu.org/problemnew/solution/P1018?page=7數組

 

題目:P1018【乘積最大】函數


 

前言:spa

  • 這題的正解理論上說是DP,但是因爲民間數據太水,用暴力過並不難

總體思路:code

  1. 利用一個b數組標記每一位之間是否分割(1位分割,0爲鏈接)。
  2. 利用STL裏的 next_permutation 求出b的各類排列(即暴力枚舉每種狀況)。
  3. 因爲本題數據規模大,因此要使用高精度計算每種分割的最後結果,並找出最大。

 

next_permutation函數:

  • 即STL裏的求全排列函數,所求的數組必須是升序,不然將沒法求出所有的排列方式(這和它生成羣排列的方式有關),next_permutation正常和sort同樣,有2個參數,分別是數組的首地址和尾地址,並返回一個bool量,即可否求出下一個全排列,能夠的話返回true,並將指定數組變爲下一個排列方式,如1 2 3的下一個排列方式就是 1 3 2。

 

上代碼:blog

#include<algorithm> //使用next_permutation須要調用的頭文件
#include<cstdio>  //c語言讀入輸出
#include<cstring>  //處理高精度字符串時須要用到

using namespace std;

struct BigN{  //高精度(即大整數)運算
    int num[1001]={0},len;
    BigN(char s[])  //構造函數,用於給新定義的大整數賦值
    {
        len=strlen(s);
        for(int i=len-1;i>=0;i--)
            num[i]=s[len-i-1]-'0';
    }
    void clean()  //用於清零
    {
        memset(num,0,sizeof(num));
    }
    void f(int n)  //將一個普通整數壓到大整數的開頭,這個在後面分割每一位時會用到
    {
        for(int i=len;i>0;i--)
            num[i]=num[i-1];
        len++;
        num[0]=n;
    }
    void cheng(BigN n)//高精度乘法,這裏就不過多解釋了,有疑問能夠前往 P1303 瞭解更多
    {
        BigN c("0");
        int s=0,g=0;
        for(int i=0;i<=len;i++)
            for(int j=0;j<=n.len;j++)
            {
                int w=i+j;
                s=num[i]*n.num[j];
                c.num[w]+=s%10;
                c.num[w+1]+=s/10+c.num[w]/10;
                c.num[w]%=10;
            }
        c.len=len+n.len;
        while(c.num[c.len]==0&&c.len>=0)c.len--;
        fz(c);
    }
    void fz(BigN n) //將一個大整數賦值給例外一個大整數,至關於'='
    {
        len=n.len;
        for(int i=0;i<=n.len;i++)
            num[i]=n.num[i];
    }
    bool bj(BigN n)  //判斷兩個大整數的大小,用於找出最大結果
    {
        if(len>n.len)
            return 1;
        else if(len<n.len)
            return 0;
        else
        {
            for(int i=len;i>=0;i--)
                if(num[i]<n.num[i])
                    return 0;
                else if(num[i]>n.num[i])
                    return 1;
            return -1;
        }
    }
    void out() //輸出
    {
        for(int i=len;i>=0;i--)
            printf("%d",num[i]);
    }
};

int n,k,sum[55],b[55],i,j; //常規定義,很少作解釋
BigN mmax("0");

int main()
{
    char s[101];  //s用於讀入一個大整數
    scanf("%d%d%s",&n,&k,&s);
    for(i=0;i<strlen(s);i++)  //在sum中備份一份原數
        sum[i]=s[i]-'0';
    for(i=n-2;i>=(n-k)-1;i--)  //將b數組中的後k個數賦1,由於使用next_permutation須要讓數組升序,不然可能沒法找出全部排列方式
        b[i]=1;
    do{
        BigN temp("0"),all("1");//temp用於存放分割後的每一節,all用於計算每種排列方式的結果
        i=0;
        while(i<n)//分割
        {
            if(i!=0)
                if(b[i-1]==1)//若是b[i-1]爲1,那麼就要在這一位加上一個乘號,即將原數分割
                    all.cheng(temp),temp.clean();//總數乘上分割後的每一位,並將temp清空,用於儲存下一節.
            temp.f(sum[i]),i++; //將原數的下一位壓到temp的最前面
        }
        all.cheng(temp);//因爲temp尚未乘all就退出循環,因此要再乘一次
        if(mmax.bj(all)==0)//若是這種排列順序的結果大於以前最大的結果,刷新最大結果
            mmax.fz(all);
    }while(next_permutation(b,b+n-1));//調用next_permutation
    mmax.out();//輸出
    return 0;
}
相關文章
相關標籤/搜索