E~G Java题解,代码已去除冗余~~~
类似于状态机类型的动态规划,此处对于每一步,只有两种状态,且转移是线性,时间复杂度O(n)
import java.util.*;
public class Main{
public static void main(String args[]){
Scanner sc=new Scanner(System.in);
int n=sc.nextInt(),k=sc.nextInt();
long ab[][]=new long[n][2];
for(int i=0;i<2;i++){
for(int j=0;j<n;j++){
ab[j][i]=sc.nextInt();
}
}
ab[0][1]=-(long)1e18;
for(int i=1;i<n;i++){
long cur[]=ab[i].clone();
for(int j=0;j<2;j++){
ab[i][j]+=ab[i-1][j];
if(ab[i-1][j^1]>=k){
ab[i][j]=Math.max(ab[i][j],ab[i-1][j^1]-k+cur[j]);
}
}
}
System.out.println(Math.max(ab[n-1][0],ab[n-1][1]));
}
}
对于每一对儿非0之间的数,从小的一侧往大的一次递增填充数字,直到大于较大一侧,开始上下震荡填充,时间复杂度O(n)
import java.util.*;
public class Main{
public static void main(String args[]){
Scanner sc=new Scanner(System.in);
int n=sc.nextInt(),a[]=new int[n+5];
a[0]=a[n+1]=(int)1e6;
for(int i=1;i<=n;i++){
a[i]=sc.nextInt();
}
for(int i=0,j=1;i<=n;i=j,j++){
while(j<=n+1&&a[j]==0){
j++;
}
if(a[i]<=a[j]){
for(int k=i+1;k<j;k++){
a[k]=a[k-1]<=a[j]?a[k-1]+1:a[k-1]-1;
}
}
else{
for(int k=j-1;k>i;k--){
a[k]=a[k+1]<=a[i]?a[k+1]+1:a[k+1]-1;
}
}
}
for(int i=2;i<=n;i++){
if(Math.abs(a[i]-a[i-1])!=1){
System.out.println("-1");
return;
}
}
for(int i=1;i<=n;i++){
System.out.print(a[i]+" ");
}
}
}
以“根左右”的方式深搜重新排列树节点,同时记录子节点路径的最大路径和,再将新的排列计算排列计算前缀和后缀最大值,对于每一个询问,可以单位时间计算答案,时间复杂度O(n+q)
import java.util.*;
public class Main{
public static void main(String args[]){
Scanner sc=new Scanner(System.in);
int n=sc.nextInt(),q=sc.nextInt(),p[]=new int[n+5],l[]=new int[n+5],r[]=new int[n+5];
long a[]=new long[n+5],max[]=new long[n+5],pre[]=new long[n+5],suf[]=new long[n+5];
List<Integer> path[]=new List[n+5];
for(int i=1;i<=n;i++){
path[i]=new ArrayList<>();
a[i]=sc.nextInt();
}
for(int i=2;i<=n;i++){
p[i]=sc.nextInt();
path[p[i]].add(i);
}
find(1,1,path,a,max,pre,suf,l,r);
for(int i=1;i<=n;i++){
pre[i]=Math.max(pre[i],pre[i-1]);
suf[n+1-i]=Math.max(suf[n+1-i],suf[n+2-i]);
}
for(int i=0;i<q;i++){
int x=sc.nextInt(),y=sc.nextInt();
System.out.println(Math.max(Math.max(pre[l[x]-1],suf[r[x]+1]),max[x]-a[p[x]]+a[y]));
}
}
static int find(int k,int idx,List<Integer> path[],long a[],long max[],long pre[],long suf[],int l[],int r[]){
r[k]=l[k]=idx;
max[k]=pre[idx]=suf[idx]=a[k];
for(int b:path[k]){
a[b]+=a[k];
r[k]=find(b,r[k]+1,path,a,max,pre,suf,l,r);
max[k]=Math.max(max[k],max[b]);
}
return r[k];
}
}
另外可用线段树维护区间最大值,时间复杂度O((n+q)logn)
,参考代码