本意是同时提供java以及c++两种语言的代码的题解
但是无奈oj网站一直欺负java语言慢, 因此本篇题解部分java代码只提供思路参考
不提供语言优化,有兴趣的同学可以自行优化java版本
过不了的java语言均已注明!
目录
4546. 最大和加强加强版 - 线性dp
题目:
思路:
定义 f[i][j][k] :前 i 个数,构成 j 个组,且第 i 个数是否在第 j 个组(0/1表示是否存在)
属性:最大值max
状态划分:
(1)选择第i个数
- 第 i 个数在新开的组(前i-1个数已经构成j-1组)
- f[i][j][1] = max( f[i-1][j-1][0],f[i-1][j-1][1] )+ w[i]
- 第 i 个数在旧组(前i-1个数已经构成j组)
- f[i][j][1] = max( f[i][j][1],f[i-1][j][1]+w[i] )
(2)不选择第i个数
- f[i][j][0] = max( f[i-1][j][0],f[i-1][j][1] )
根据状态定义知答案为max(f[n][m][0],f[n][m][1])
因为i只与i-1层有关,所以可以进行优化&1
java版 - 这个vjudge过不了 acw可以过
import java.util.*;
class Main
{
static int N=1000010,M=1010;
static long[][][] f=new long[2][M][2]; //f[i][j][k]前i个数,分成j组,第i个数是否在第j组(0/1表示)
static int[] w=new int[N];
public static void main(String[] args)
{
Scanner sc=new Scanner(System.in);
while(sc.hasNextLine())
{
String[] s=sc.nextLine().split(" ");
int m=Integer.parseInt(s[0]);
int n=Integer.parseInt(s[1]);
int cnt=2;
for(int i=1;i<=n;i++) w[i]=Integer.parseInt(s[cnt++]);
for(int i=0;i<2;i++)
for(int j=0;j<M;j++) Arrays.fill(f[i][j],-0x3f3f3f3f);
f[0&1][0][0]=0;
for(int i=1;i<=n;i++)
{
f[i&1][0][0]=0;
for(int j=1;j<=m;j++)
{
//选择第i个数且第i个数在新开的组j (前i-1个数已经凑成j-1组)
f[i&1][j][1]=Math.max(f[i-1&1][j-1][1],f[i-1&1][j-1][0])+w[i];
//选择第i个数且第i个数插在旧组j最后 (前i-1个数已经凑成j组)
f[i&1][j][1]=Math.max(f[i&1][j][1],f[i-1&1][j][1]+w[i]);
//不选择第i个数 (前i-1个数已经凑成j组)
f[i&1][j][0]=Math.max(f[i-1&1][j][1],f[i-1&1][j][0]);
}
}
System.out.println(Math.max(f[n&1][m][0],f[n&1][m][1]));
}
}
}
c++版
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <cmath>
#include <deque>
using namespace std;
#define int long long
#define max(a,b) (a>b?a:b)
#define io ios_base::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr)
const int N=1e6+10,M=1010;
int f[2][M][2];
int w[N];
int n,m;
signed main()
{
io;
while(cin>>m>>n)
{
for(int i=1;i<=n;i++) cin>>w[i];
memset(f,-0x7f,sizeof f);
f[0][0][0]=0;
for(int i=1;i<=n;i++)
{
f[i&1][0][0]=0;
for(int j=1;j<=m;j++)
{
f[i&1][j][1]=max(f[i-1&1][j-1][0],f[i-1&1][j-1][1])+w[i];
f[i&1][j][1]=max(f[i&1][j][1],f[i-1&1][j][1]+w[i]);
f[i&1][j][0]=max(f[i-1&1][j][1],f[i-1&1][j][0]);
}
}
cout<<max(f[n&1][m][0],f[n&1][m][1])<<endl;
}
}
4547. 伊格内修斯和公主IV - 摩尔投票法
题目:
思路:
摩尔投票法的经典应用
如果有一个数x出现次数超过一半,则通过1v1打擂台的方式
与和x不同的数两两抵消后仍然存在
原因是因为x超过一半,其他数和它同归于尽后,最后生存下来的绝对是x
java版 - 超时tle 只提供思路
import java.util.*;
class Main
{
public static void main(String[] args)
{
Scanner sc=new Scanner(System.in);
while(sc.hasNext())
{
int num=0,res=0;
int n=sc.nextInt();
while(n-->0)
{
int cur=sc.nextInt();
if(res==0) //第一个人当擂主
{
res=cur;
num=1;
}else if(cur!=res)
{
num--; //同归于尽
if(num==0) //如果擂主挂了 换新擂主
{
res=cur;
num=1;
}
}else num++;
}
System.out.println(res);
}
}
}
c++版
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <cmath>
#include <deque>
using namespace std;
#define int long long
#define io ios_base::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr)
signed main()
{
io;
int n;
while(cin>>n)
{
int num=0,res=0;
while(n--)
{
int cur;
cin>>cur;
if(!res) //第一个直接当擂主
{
res=cur;
num=1;
}else if(res!=cur)
{
num--; //与挑战者同归于尽
if(!num) res=cur,num=1; //如果擂主挂了换新擂主
}else num++;
}
cout<<res<<endl;
}
}
4548. 猴子和香蕉 - 二维最长上升子序列dp
题目:
思路:
f[i]:前i个积木能堆起来的最大高度
先将每组数据的长宽高能摆放的所有情况存入数组
2种朝向×3种底面=6种摆放情况
按长宽从小到大排序,寻找满足 " 长和宽均递增 " 的最长上升子序列长度
不熟悉最长上升子序列dp模板的同学,可以学习一下:
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <cmath>
#include <deque>
using namespace std;
//#define int long long
#define io ios_base::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr)
const int N=31*6; //一共n组数据 每组数据有2种朝向和3种底面
int f[N]; //f[i]表示前i个积木堆叠的最大高度
int n,m;
typedef struct
{
int x,y,z;
}cube;
bool cmp(cube a,cube b)
{
if(a.x!=b.x) return a.x<b.x;
return a.y<b.y;
}
signed main()
{
io;
int cnt=0;
cube a[N];
while(cin>>n&&n)
{
cnt++;
for(int i=1;i<=n;i++)
{
int x,y,z;
cin>>x>>y>>z;
a[i].x=x,a[i].y=y,a[i].z=z;
a[i+n].x=x,a[i+n].y=z,a[i+n].z=y;
a[i+2*n].x=y,a[i+2*n].y=x,a[i+2*n].z=z;
a[i+3*n].x=y,a[i+3*n].y=z,a[i+3*n].z=x;
a[i+4*n].x=z,a[i+4*n].y=x,a[i+4*n].z=y;
a[i+5*n].x=z,a[i+5*n].y=y,a[i+5*n].z=x;
f[i]=0;
}
sort(a+1,a+1+n*6,cmp); //按长和宽从小到大排序
int res=0;
for(int i=1;i<=n*6;i++)
{
f[i]=a[i].z;
for(int j=1;j<i;j++)
if(a[i].x>a[j].x&&a[i].y>a[j].y)
f[i]=max(f[i],f[j]+a[i].z);
res=max(res,f[i]);
}
cout<<"Case "<<cnt<<": maximum height = "<<res<<endl;
}
}