文章目录
题目链接
知识汇总
题目列表
快输模板
import java.io.*;
import java.util.*;
import java.util.regex.*;
public class Main {
static class FastReader {
BufferedReader br;
StringTokenizer st;
public FastReader() {
br = new BufferedReader(new InputStreamReader(System.in));
}
String next() {
while (st == null || !st.hasMoreElements()) {
try {
st = new StringTokenizer(br.readLine());
} catch (IOException e) {
e.printStackTrace();
}
}
return st.nextToken();
}
int nextInt() {
return Integer.parseInt(next());
}
long nextLong() {
return Long.parseLong(next());
}
double nextDouble() {
return Double.parseDouble(next());
}
String nextLine() {
String str = "";
try {
str = br.readLine();
} catch (IOException e) {
e.printStackTrace();
}
return str;
}
boolean hasNext() {
if (st != null && st.hasMoreTokens())
return true;
try {
st = new StringTokenizer(br.readLine());
} catch (Exception e) {
return false;
}
return true;
}
}
static PrintWriter out = new PrintWriter(
new BufferedWriter(new OutputStreamWriter(System.out)));
/*
核心代码区
*/
}
A - 上台阶2
static long dp[];
static int mod=100003;
public static void main(String[] args) {
FastReader sc = new FastReader();
int n=sc.nextInt();
dp=new long[n+1];
for(int i=1;i<=n;i++){
if(i<=2)dp[i]=1;
else if(i==3)dp[i]=dp[i-1]+1;
else if(i==4)dp[i]=dp[i-1]+dp[i-3];
else if(i==5)dp[i]=dp[i-1]+dp[i-3]+1;
else dp[i]=(dp[i-1]+dp[i-3]+dp[i-5])%mod;
}
out.println(dp[n]);
out.flush();
}
B - 数字三角形
static int map[][];
static int n;
public static void main(String[] args) {
FastReader sc = new FastReader();
n=sc.nextInt();
map=new int[n+1][n+1];
for(int i=1;i<=n;i++)
for(int j=1;j<=i;j++)
map[i][j]=sc.nextInt();
dp();
out.println(getMax());
out.flush();
}
public static void dp(){
for(int i=2;i<=n;i++)
for(int j=1;j<=i;j++)
map[i][j]=Math.max(map[i-1][j-1],map[i-1][j])+map[i][j];
}
public static int getMax(){
int max=map[n][1];
for(int i=2;i<=n;i++)
if(map[n][i]>max) max=map[n][i];
return max;
}
C - 矩阵取数问题
static int map[][];
static int n;
public static void main(String[] args) {
FastReader sc = new FastReader();
n=sc.nextInt();
map=new int[n+1][n+1];
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
map[i][j]=sc.nextInt();
dp();
out.println(getMax());
out.flush();
}
public static void dp(){
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
map[i][j]=Math.max(map[i-1][j],map[i][j-1])+map[i][j];
}
public static int getMax(){
int max=map[n][1];
for(int i=2;i<=n;i++)
if(map[n][i]>max) max=map[n][i];
return max;
}
D - 背包问题(01背包)
static int dp[],w[],p[];//w[]容积数组,p[]价值数组
static int n,w0;//数量,容量
public static void main(String[] args) {
FastReader sc = new FastReader();
n=sc.nextInt();
w0=sc.nextInt();
//dp数组:放入容量为v的背包中的最大价值
dp=new int[w0+1];
w=new int[n+1];
p=new int[n+1];
for(int i=1;i<=n;i++){
w[i]=sc.nextInt();
p[i]=sc.nextInt();
}
for(int i=1;i<=n;i++){
for(int v=w0;v>0;v--){
if(v>=w[i])
dp[v]=Math.max(dp[v],dp[v-w[i]]+p[i]);
}
}
out.println(dp[w0]);
out.flush();
}
E - 完全背包
static int dp[],w[],p[];//w[]容积数组,p[]价值数组
static int n,w0;//数量,容量
public static void main(String[] args) {
FastReader sc = new FastReader();
n=sc.nextInt();
w0=sc.nextInt();
//dp数组:放入容量为v的背包中的最大价值
dp=new int[w0+1];
w=new int[n+1];
p=new int[n+1];
for(int i=1;i<=n;i++){
w[i]=sc.nextInt();
p[i]=sc.nextInt();
}
for(int i=1;i<=n;i++){
for(int v=w[i];v<=w0;v++){
if(v>=w[i])
dp[v]=Math.max(dp[v],dp[v-w[i]]+p[i]);
}
}
out.println(dp[w0]);
out.flush();
}
F - 背包问题 V2
static int dp[],w[],p[];//w[]容积数组,p[]价值数组
static int n,w0,n1;//数量,容量,计数器
public static void main(String[] args) {
FastReader sc = new FastReader();
n=sc.nextInt();
w0=sc.nextInt();
//dp数组:放入容量为v的背包中的最大价值
dp=new int[w0+1];
w=new int[2000010];
p=new int[2000010];
for(int i=1;i<=n;i++){
int ww=sc.nextInt();//体积
int pp=sc.nextInt();//价值
int c=sc.nextInt();//第i件物品数量
int t=1;
while (c>=t) {
w[++n1]=ww*t;//相当于n1++; w[n1]=w[i]*t;
p[n1]=pp*t;
c-=t;
t*=2;
}
w[++n1]=ww*c;
p[n1]=pp*c;
}
for(int i=1;i<=n1;i++){
for(int v=w0;v>=w[i]/*终止条件更改到for语句中*/;v--){
dp[v]=Math.max(dp[v],dp[v-w[i]]+p[i]);
}
}
out.println(dp[w0]);
out.flush();
}
G - 最长上升子序列
//dp[n]:代表以第n个元素结尾的LIS序列的长度
static int dp[],a[];
static int n;
public static void main(String[] args) {
FastReader sc = new FastReader();
n=sc.nextInt();
dp=new int[n];
a=new int[n];
for(int i=0;i<n;i++) a[i]=sc.nextInt();
dp[0]=1;
for(int i=1;i<n;i++) {
int t=0;
for(int j=0;j<i;j++) {
if(a[j]<a[i]) {
if(t<dp[j])t=dp[j];
}
}
dp[i]=t+1;
}
int t=0;
for(int i=0;i<n;i++) {
if(t<dp[i])t=dp[i];
}
out.println(t);
out.flush();
}
H - 最长公共子序列
/*
状态转移方程如下:
x[i]=y[i]: dp[i][j]=dp[i-1][j-1]+1
x[i]!=y[j]: dp[i][j]=max(dp[i-1][j],dp[i][j-1])
i=0||j=0: dp[i][j]=0
*/
static char c1[],c2[];
static int n,m;
static int dp[][];
public static void main(String[] args) {
FastReader sc = new FastReader();
c1=(" "+sc.next()).toCharArray();
c2=(" "+sc.next()).toCharArray();
n=c1.length-1;m=c2.length-1;
//dp[i][j]:字符串1的前i位和字符串2的前j位的LCS长度
dp=new int[n+1][m+1];
for(int i=1;i<=n;i++) {
for(int j=1;j<=m;j++) {
if(c1[i]==c2[j]) {
dp[i][j]=dp[i-1][j-1]+1;
}
else {
dp[i][j]=Math.max(dp[i-1][j],dp[i][j-1]);
}
}
}
dfs(n,m);
out.println();
out.flush();
}
public static int dfs(int i,int j) {
//字符串第一位均是空位,不算
if(i==0||j==0) return 0;
if(c1[i]==c2[j]){
dfs(i-1,j-1);
out.print(c1[i]);
}
else{
if(dp[i-1][j]>dp[i][j-1])dfs(i-1,j);
else dfs(i,j-1);
}
return 0;
}
I - 石子合并(环形合并)
static int n,minl,maxl;//n堆石子
//f[i][j]:表示从i到j堆石子合并后的最大f1/最小得分f2
static int num[],s[],f1[][],f2[][];
//转移方程:f[i][j] = max(f[i][k]+f[k+1][j]+d[i][j];
//d(i,j)表示从i到j石子个数的和
public static void main(String[] args) {
FastReader sc = new FastReader();
n=sc.nextInt();
int N=2*n+1;
//因为是一个环,所以需要开到两倍再枚举分界线,最后肯定是最大的
num=new int[N];
s=new int[N];
f1=new int[N][N];//max
f2=new int[N][N];//min
for(int i=1;i<=n+n;i++){
if(i<=n){
num[i]=sc.nextInt();
num[i+n]=num[i];
}
s[i]=s[i-1]+num[i];
}
for(int p=1;p<n;p++) {
for(int i=1,j=i+p;(j<n+n) && (i<n+n);i++,j=i+p) {
f2[i][j]=999999999;
for(int k=i;k<j;k++)
{
f1[i][j] = Math.max(f1[i][j], f1[i][k]+f1[k+1][j]+d(i,j));
f2[i][j] = Math.min(f2[i][j], f2[i][k]+f2[k+1][j]+d(i,j));
}
}
}
minl=999999999;
for(int i=1;i<=n;i++)
{
maxl=Math.max(maxl,f1[i][i+n-1]);
minl=Math.min(minl,f2[i][i+n-1]);
}
out.printf("%d\n%d",minl,maxl);
out.flush();
}
public static int d(int i,int j){return s[j]-s[i-1];}
J - 循环数组最大子段和
public static void main(String[] args) {
FastReader sc = new FastReader();
int n=sc.nextInt();
long sum=0;
int num[]=new int[n+1];
for(int i=0;i<n;i++){
num[i]=sc.nextInt();
sum+=num[i];
}
//样例超出int范围
long dp[]=new long[n];
for(int i=0;i<n;i++)//找最大子段
if(i>0&&dp[i-1]>0)
dp[i]=dp[i-1]+num[i];
else
dp[i]=num[i];
long min=(int)1e9+7,max=0;
for(int i=0;i<n;i++)
if(max<dp[i])
max=dp[i];
for(int i=0;i<n;i++)//找最小子段
if(i>0&&dp[i-1]<0)
dp[i]=dp[i-1]+num[i];
else
dp[i]=num[i];
for(int i=0;i<n;i++)
if(min>dp[i])
min=dp[i];
min=sum-min;
out.println(Math.max(min,max));
out.flush();
}
K - 没有上司的舞会
查了一下,大概是这样的操作不安全,可能使程序崩溃。
改成用结点类封装list,再进行操作就编译通过了。
ps:如果用二维数组代替list的功能可能会MLE(甚至出现了RE :- ()
//主程序
static node tree[];
static int ri[],vis[],f[][];//ri[]快乐指数
static int n;//总人数
//f[i][0]:i不来的情况下以i为根节点的子树的最大快乐值
//f[i][1]:i来的情况下以i为根节点的子树的最大快乐值
public static void main(String[] args) {
FastReader sc = new FastReader();
n=sc.nextInt();
ri=new int[n+1];
vis=new int[n+1];
tree=new node[n+1];
f=new int[n+1][2];
for(int i=1;i<=n;i++)ri[i]=sc.nextInt();
for(int i=1;i<n;i++){
int x=sc.nextInt();
int y=sc.nextInt();
if(tree[x]==null)tree[x]=new node();
if(tree[y]==null)tree[y]=new node();
tree[x].ad(y);
tree[y].ad(x);
}
dfs(1);//从根节点找子树
out.println(Math.max(f[1][0],f[1][1]));
out.flush();
}
public static void dfs(int x){
vis[x]=1;
f[x][0]=0;
f[x][1]=ri[x];
for(int i=0;i<tree[x].length;i++){
int son=tree[x].gt(i);
if(vis[son]!=0)continue;
dfs(son);
f[x][0]+=Math.max(f[son][0],f[son][1]);
f[x][1]+=f[son][0];
}
}
//结点类
class node{
int length;
List<Integer> ls;
public node() {
ls=new ArrayList<>();
length=0;
}
public void ad(int x){
ls.add(x);
length++;
}
public int gt(int x){
return ls.get(x);
}
}
L - 滑雪
static int n,m;//row & column
static int dp[][]=new int[110][110];
static int mp[][]=new int[110][110];//地图(高度)
static int dir[][]={{1,0},{-1,0},{0,-1},{0,1}};//搜索方向
public static void main(String[] args) {
FastReader sc = new FastReader();
int i,j;
n=sc.nextInt();
m=sc.nextInt();
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
mp[i][j]=sc.nextInt();
int s=0;
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
s=Math.max(find(i,j), s);
out.printf("%d\n",s);
out.flush();
}
public static int find(int x,int y) //找出从该点开始能进行的最大次数
{
if(dp[x][y]!=0)
return dp[x][y];
int d=1,tx,ty;
for(int k=0;k<4;k++)
{
tx=x+dir[k][0];
ty=y+dir[k][1];
if(tx>=1&&tx<=n&&ty>=1&&ty<=m&&mp[x][y]>mp[tx][ty])
d=Math.max(find(tx,ty)+1,d);
}
dp[x][y]=d;
return d;
}