• 暑假集训Day1 整数划分


    题目大意:

    如何把一个正整数N(N长度<20)划分为M(M>=1)个部分,使这M个部分的乘积最大。N、M从键盘输入,输出最大值及一种划分方式。

    输入格式:

    第一行一个正整数T(T<=10000),表示有T组数据。

    接下来T行每行两个正整数N,M。

    输出格式

    对于每组数据

    第一行输出最大值。

    第二行输出划分方案,将N按顺序分成M个数输出,两个数之间用空格格开。

    算法分析:

    第一问求dp值就是简单的dp 具体实现可参见 暑假集训day1 水题 乘法最大

    1.做第一问的时候注意这个题给出的M并不是乘号数量而是分成的份数,所以读入M之后记得M-1,到后面便历乘号数量j的时候也是min(i-1,m)。
    2.记录路径的方法也跟平时记录路径一样,如果更改了dp的值说明在这个位置插入了乘号,就让path[i][j] = k(k记录断点,i记录前i个数字,j表示共有j个乘号)
    3.最后递归输出就可以了,递归函数传参x为当前为前x个数字,t表示还有t个乘号没有插入
    (注意一个细节,递归边界是t=-1而不是t=0,因为t等于0的时候表示的是有0个乘号但是仍然是分成一份,即仍然有值,只有当t遍历到-1的时候才说明没有东西可以递归了)

    代码展示

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn = 1e3+10;
    int a[maxn],n,T,path[maxn][maxn],m;
    long long dp[maxn][maxn],sum[maxn][maxn];
    char s[maxn];
    
    void clear(){
    	n = strlen(s+1);
    	memset(sum,0,sizeof(sum));
    	memset(dp,0,sizeof(dp));
    	for(int i = 1;i <= n;++i)
    			for(int j = i;j <= n;++j)
    				sum[i][j] = sum[i][j-1]*10 + s[j] - '0';
    	for(int i = 1;i <= n;++i)dp[i][0] = sum[1][i];
    	return ;
    }
    
    void Path(int x,int t){
    	if(t == -1)return;
    	Path(path[x][t],t-1);
    	printf("%lld ",sum[path[x][t]+1][x]);
    }
    
    int main(){
    	scanf("%d",&T);
    	while(T--){
    		scanf("%s %d",s+1,&m);m--;
    		clear();
    		for(int i = 1;i <= n;++i){
    			for(int j = 1;j <= min(i-1,m);++j)
    				for(int k = 1;k < i;++k){
    					if(dp[i][j] < dp[k][j-1]*sum[k+1][i]){
    						dp[i][j] = dp[k][j-1]*sum[k+1][i];
    						path[i][j] = k;
    					}
    				}
    		}
    		printf("%lld
    ",dp[n][m]);
    		Path(n,m);
    		printf("
    ");
    	}
    	return 0;
    }
    

    制作不易,关注走起>)<

  • 相关阅读:
    1006: [HNOI2008]神奇的国度
    1003: [ZJOI2006]物流运输trans
    Task 6.2冲刺会议六 /2015-5-19
    Task 6.2冲刺会议五 /2015-5-18
    Task 6.2冲刺会议四 /2015-5-17
    Task 6.3 场景调研
    Task 8 找水王
    Task 6.2站立会议三
    Task 6.2站立会议二
    Task 6.2站立会议一
  • 原文地址:https://www.cnblogs.com/2004-08-20/p/13184497.html
Copyright © 2020-2023  润新知