NOJ-1203-装盘子 & NOJ-1576-最大连续子序列和问题

156 阅读1分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

装盘子

描述

N人为了大快朵颐,行至云餐二楼,取了N个盘子,打了M个饺子。现欲将M个饺子装入N个盘子中,试问共有多少种不同的装法? 假设盘子足够大,并且盘子里可以什么都不放。注意像2 5 0和5 0 2之类的属于同一种放法。

输入

两个整数M、N(1=< M,N <=100)以空格隔开。

输出

单独一行输出共有几种装法。

输入样例

7 3

输出样例

8

提示

注意输出要以“\n”结尾。

思路

问m个饺子放到n个盘子的方法,这个题直接写动态转移方程不好写,那就换成写记忆化搜索就行了。考虑m>=n和m<n两种情况。dfs(int resn ,int resm)表示剩余resn个盘子,剩余resm个饺子的放置种类数目,dp[resn][resm]对其进行记录,一旦dp[resn][resm]遍历过,就直接返回即可,优化时间复杂度。m<n的话肯定有n-m个盘子都是空的ans=dfs(rem,rem)。m>=n的话可以一个盘子不妨饺子即dfs(resn-1,resm ),也可以将每个盘子都至少放一个饺子即dfs(resn,resm-resn).由dfs(resn-1,resm)不断搜索下去可以对不同数量的空盘子均可以遍历到。最后答案就是dfs(n,m).

代码

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=100+50;
int n,m,dp[maxn][maxn];
int dfs(int resn,int resm){
    if(resn==1||resm==1||resm==0)return 1;
    if(dp[resn][resm])return dp[resn][resm];
    int ans=0;
    if(resm<resn)ans=dfs(resm,resm);
    else ans=dfs(resn-1,resm)+dfs(resn,resm-resn);
    dp[resn][resm]=ans;
    return ans;
}
int main(){
    cin>>m>>n;
    cout<<dfs(n,m)<<endl;
    return 0;
}

最大连续子序列和问题

描述

给定一整数序列A0,A1, A2,... An-1 (可能有负数),求A0~An-1的一个连续子序列Ai ~Aj,使得Ai到Aj的和最大。

输入

先输入一个正整数n(1<n<1000),再输入n个整数。

输出

输出最大连续子序列的和。

输入样例

102 -1 5 -7 2 -1 4 -2 4 -5

输出样例

7

思路

代码还没有AC,NOJ评测机炸了,但是这个O(n)的思路大概是对的:sum[i]为前i个数字的连续子序列的最大和。如果sum[i-1]<0,那对于sum[i]就没必要加上前i-1的总和了,因为这样对答案的贡献还不如0.如果sum[i-1]>0,则sum[i]=sum[i-1]+a[i].ans=max(ans,sum[i]);

代码

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=10000+50;
int n,a[maxn],sum[maxn];
int max(int x,int y){
	if(x>=y)return x;
	return y;
}
int main(){
	int i;
	cin>>n;
	for(i=1;i<=n;i++)cin>>a[i];
	int ans=0;
	for(i=1;i<=n;i++){
		if(sum[i-1]>0)sum[i]=sum[i-1]+a[i];
		else sum[i]=a[i];
		ans=max(ans,sum[i]);
	}
	cout<<ans<<endl;
	return 0;
}