NYOJ746 整数划分(四)(深搜DFS,区间DP)
2017-07-31 16:23
513 查看
题目;
时间限制:1000 ms | 内存限制:65535 KB
难度:3
描述
暑假来了,hrdv 又要留学校在参加ACM集训了,集训的生活非常Happy
![](http://acm.nyist.net/JudgeOnline/admin/kind/plugins/emoticons/5.gif)
(ps:你懂得),可是他最近遇到了一个难题,让他百思不得其解,他非常郁闷。。亲爱的你能帮帮他吗?
问题是我们经常见到的整数划分,给出两个整数 n , m ,要求在 n 中加入m - 1 个乘号,将n分成m段,求出这m段的最大乘积
输入第一行是一个整数T,表示有T组测试数据
接下来T行,每行有两个正整数 n,m ( 1<= n < 10^19, 0 < m <= n的位数);
输出输出每组测试样例结果为一个整数占一行
样例输入
样例输出
来源经典题目
思路:
搜索的思路就不说了,先初始化一下每一个区间的值,然后再相乘就好。
DP的思路是先预处理出每一个区间的值。
然后用dp[i][j]表示把0~i这个区间划分成j段所能获得的最大乘积。
则:
dp[i][j]=max(dp[i][j],dp[k][j-1]*sum[k+1][i])
代码1(dfs):
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <string>
#include <iostream>
#include <stack>
#include <queue>
#include <vector>
#include <algorithm>
#define mem(a,b) memset(a,b,sizeof(a))
#define N 100000+10
#define M 10000+20
#define MOD 1000000000+7
#define inf 0x3f3f3f3f
#define ll long long
using namespace std;
char s[100];
ll sum[100][100];
ll len,maxx,n,m;
void dfs(ll i,ll ans,ll step)
{
if(step==m)
{
maxx=max(ans,maxx);
return;
}
for(ll j=1; j<=len-m+1; j++)//i和j是区间
if(i+j<=len)
dfs(i+j,ans*sum[i+1][i+j],step+1);
}
int main()
{
ll t;
scanf("%lld",&t);
while(t--)
{
maxx=0;
scanf("%s%lld",s+1,&m);
len=strlen(s+1);
for(ll i=1; i<=len; i++)
{
sum[i][i]=s[i]-'0';
for(ll j=i+1; j<=len; j++)
sum[i][j]=sum[i][j-1]*10+s[j]-'0';
}
dfs(0,1,0);
printf("%lld\n",maxx);
}
return 0;
}
代码2(DP):
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <string>
#include <iostream>
#include <stack>
#include <queue>
#include <vector>
#include <algorithm>
#define mem(a,b) memset(a,b,sizeof(a))
#define N 100000+10
#define M 10000+20
#define MOD 1000000000+7
#define inf 0x3f3f3f3f
#define ll long long
using namespace std;
char s[100];
ll sum[100][100],dp[100][100];
ll n,m;
int main()
{
ll t;
scanf("%lld",&t);
while(t--)
{
mem(dp,0);
scanf("%s%lld",s,&m);
n=strlen(s);
for(ll i=0; i<n; i++)
{
sum[i][i]=s[i]-'0';
for(ll j=i+1; j<n; j++)
sum[i][j]=sum[i][j-1]*10+s[j]-'0';
}
for(ll i=0; i<n; i++)
{
dp[i][1]=sum[0][i];
for(ll j=2; j<=m; j++) //枚举段数
for(ll k=j-2; k<i; k++)
dp[i][j]=max(dp[i][j],dp[k][j-1]*sum[k+1][i]);
}
printf("%lld\n",dp[n-1][m]);
}
return 0;
}
整数划分(四)
时间限制:1000 ms | 内存限制:65535 KB难度:3
描述
暑假来了,hrdv 又要留学校在参加ACM集训了,集训的生活非常Happy
![](http://acm.nyist.net/JudgeOnline/admin/kind/plugins/emoticons/5.gif)
(ps:你懂得),可是他最近遇到了一个难题,让他百思不得其解,他非常郁闷。。亲爱的你能帮帮他吗?
问题是我们经常见到的整数划分,给出两个整数 n , m ,要求在 n 中加入m - 1 个乘号,将n分成m段,求出这m段的最大乘积
输入第一行是一个整数T,表示有T组测试数据
接下来T行,每行有两个正整数 n,m ( 1<= n < 10^19, 0 < m <= n的位数);
输出输出每组测试样例结果为一个整数占一行
样例输入
2 111 2 1111 2
样例输出
11 121
来源经典题目
思路:
搜索的思路就不说了,先初始化一下每一个区间的值,然后再相乘就好。
DP的思路是先预处理出每一个区间的值。
然后用dp[i][j]表示把0~i这个区间划分成j段所能获得的最大乘积。
则:
dp[i][j]=max(dp[i][j],dp[k][j-1]*sum[k+1][i])
代码1(dfs):
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <string>
#include <iostream>
#include <stack>
#include <queue>
#include <vector>
#include <algorithm>
#define mem(a,b) memset(a,b,sizeof(a))
#define N 100000+10
#define M 10000+20
#define MOD 1000000000+7
#define inf 0x3f3f3f3f
#define ll long long
using namespace std;
char s[100];
ll sum[100][100];
ll len,maxx,n,m;
void dfs(ll i,ll ans,ll step)
{
if(step==m)
{
maxx=max(ans,maxx);
return;
}
for(ll j=1; j<=len-m+1; j++)//i和j是区间
if(i+j<=len)
dfs(i+j,ans*sum[i+1][i+j],step+1);
}
int main()
{
ll t;
scanf("%lld",&t);
while(t--)
{
maxx=0;
scanf("%s%lld",s+1,&m);
len=strlen(s+1);
for(ll i=1; i<=len; i++)
{
sum[i][i]=s[i]-'0';
for(ll j=i+1; j<=len; j++)
sum[i][j]=sum[i][j-1]*10+s[j]-'0';
}
dfs(0,1,0);
printf("%lld\n",maxx);
}
return 0;
}
代码2(DP):
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <string>
#include <iostream>
#include <stack>
#include <queue>
#include <vector>
#include <algorithm>
#define mem(a,b) memset(a,b,sizeof(a))
#define N 100000+10
#define M 10000+20
#define MOD 1000000000+7
#define inf 0x3f3f3f3f
#define ll long long
using namespace std;
char s[100];
ll sum[100][100],dp[100][100];
ll n,m;
int main()
{
ll t;
scanf("%lld",&t);
while(t--)
{
mem(dp,0);
scanf("%s%lld",s,&m);
n=strlen(s);
for(ll i=0; i<n; i++)
{
sum[i][i]=s[i]-'0';
for(ll j=i+1; j<n; j++)
sum[i][j]=sum[i][j-1]*10+s[j]-'0';
}
for(ll i=0; i<n; i++)
{
dp[i][1]=sum[0][i];
for(ll j=2; j<=m; j++) //枚举段数
for(ll k=j-2; k<i; k++)
dp[i][j]=max(dp[i][j],dp[k][j-1]*sum[k+1][i]);
}
printf("%lld\n",dp[n-1][m]);
}
return 0;
}
相关文章推荐
- NYOJ 746 整数划分(四)(区间dp)
- NYOJ 746 整数划分(四)详解 (区间DP)
- nyoj746整数划分(四)【区间dp】
- NYOJ746 整数划分(区间DP)
- NYOJ746:整数划分(四)(区间dp)
- NYOJ 746 - 正整数n划分为m段,求m段的最大乘积 【区间DP】
- nyoj746整数划分(四)【区间dp】
- NYOJ 746 整数划分(区间DP)
- nyoj746 整数划分(四)【区间dp】
- nyoj 整数划分(四) 746 (区间DP)
- nyoj 746整数划分(四) 区间DP
- NYOJ 746 整数划分(四) (区间dp)
- NYOJ - 746 - 整数划分(四)(区间DP)
- 区间dp----整数划分nyoj746
- 南阳理工746整数划分(区间dp)
- NYOJ176 整数划分(二)(DP,DFS)
- 南阳理工746整数划分(区间dp)
- NYOJ 整数划分(四) (区间dp)
- 小白算法练习 dp练习001-区间dp NYOJ 石子合并,整数划分 POJ Brackets
- nyoj746 整数划分 (区间DP4)