Codeforces 984D 题解(DP)

10 篇文章 0 订阅

题面

传送门
题目大意:
给你一个计算区间f函数的公式,举例f(1,2,4,8)=f(1⊕2,2⊕4,4⊕8)=f(3,6,12)=f(3⊕6,6⊕12)=f(5,10)=f(5⊕10)=f(15)=15 然后现在给你一个数列,n<=5000,然后q个询问,q<=100000,每次询问[l,r]区间内f函数的最大值是多少

分析

此题可用DP求解
dp[i][j] d p [ i ] [ j ] 表示区间[i,j]f函数最大值
显然初始值 dp[i][i]=a[i] d p [ i ] [ i ] = a [ i ]
15
5 10
3 6 12
1 2 4 8
我们把题面例子中每个区间的f值写成一个金字塔形
从下到上为1~4行
对于每个区间[l,r],其实我们要统计的是金字塔中的一小部分的最大值
如[1,2],即求金字塔
3
1 2
的最大值,显然是3
显然可以从下到上递推写出
dp[i][j]=dp[i+1][j]xor d p [ i ] [ j ] = d p [ i + 1 ] [ j ] x o r dp[i][j1] d p [ i ] [ j − 1 ]
又因为要统计最大值
dp[i][j]=max(dp[i+1][j],dp[i][j1],dp[i][j[) d p [ i ] [ j ] = m a x ( d p [ i + 1 ] [ j ] , d p [ i ] [ j − 1 ] , d p [ i ] [ j [ )
总的状态转移方程为
dp[i][j]=max(dp[i+1][j],dp[i][j1],dp[i+1][j]xordp[i][j1]) d p [ i ] [ j ] = m a x ( d p [ i + 1 ] [ j ] , d p [ i ] [ j − 1 ] , d p [ i + 1 ] [ j ] x o r d p [ i ] [ j − 1 ] )
在代码中分步实现更方便
时间复杂度 O(n2) O ( n 2 )

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#define maxn 5005
using namespace std;
int n,q;
int dp[maxn][maxn];
int l,r;
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&dp[i][i]);
    for(int i=n;i>=1;i--){
        for(int j=i+1;j<=n;j++){
            dp[i][j]=dp[i][j-1]^dp[i+1][j];
        }
    }
    for(int i=n;i>=1;i--){
        for(int j=i+1;j<=n;j++){
            dp[i][j]=max(dp[i][j],max(dp[i][j-1],dp[i+1][j]));
        }
    }
    scanf("%d",&q);
    for(int i=1;i<=q;i++){
        scanf("%d %d",&l,&r);
        printf("%d\n",dp[l][r]);
    } 
} 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值