Codeforces 984D 题解(DP)

 

题面

传送门
题目大意:
给你一个计算区间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]dp[i][j]表示区间[i,j]f函数最大值
显然初始值dp[i][i]=a[i]dp[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]xordp[i][j]=dp[i+1][j]xor dp[i][j1]dp[i][j−1]
又因为要统计最大值
dp[i][j]=max(dp[i+1][j],dp[i][j1],dp[i][j[)dp[i][j]=max(dp[i+1][j],dp[i][j−1],dp[i][j[)
总的状态转移方程为
dp[i][j]=max(dp[i+1][j],dp[i][j1],dp[i+1][j]xordp[i][j1])dp[i][j]=max(dp[i+1][j],dp[i][j−1],dp[i+1][j]xordp[i][j−1])
在代码中分步实现更方便
时间复杂度O(n2)O(n2)

代码

#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]);
    } 
} 
posted @ 2018-05-28 19:54  birchtree  阅读(161)  评论(0编辑  收藏  举报