CodeForces - 984D XOR-pyramid(区间DP)

题目链接:CF984D
题意:定义了一个区间的值F的求法,给定你一个数组,现在要进行Q次区间查询,每次查询要输出该区间的F的最大值.
思路:
1.不知道位运算 ^ 的同学请自行百度.
2.题目中所给我们F的求法太复杂,我们现在想办法把它优化一下,如下图是根据题目给出方式的计算方法,我们求f[1][5]的值时只需要求得 f [1][4]和 f[2][5] 的值,继续向下推导,求f[1][4]和f[2][4]的值时我们需要求得f[1][3]和f[2][4],f[2][4]和f[3][5]的值,我们可以先猜想一个结论,即 f[i][j] = f[i][j-1] ^ f[i+1][j],
继续向下推导,可以得出我们的猜想是正确的,所以f[i][j]的动态转移方程为:

f [i] [j] = f [i] [j-1] ^ f [i+1] [j] (i != j)

代码实现

for(int len = 0;len<=n;len++) { // 求【l,r】的f值时应该已经求得【l,r-1】【l+1,r】的值了,所以我们先遍历长度
        for(int i=0;i+len<n;i++) {
            if(len==0) {
                f[i][i]=a[i]; 
            }
            else {
                f[i][i+len]= f[i][i+len-1]^f[i+1][i+len];
            }
        }
    }

在这里插入图片描述

3.解决了f值的求解,我们现在考虑区间中f的最大值的求解,因为要求区间【l,r】的最大值需要遍历它所有子连续区间的f值的大小,而我们有Q次询问,所以直接暴力显然是会出问题的。我们来考虑一下能否在求得 f[i][j]的值时就能得到其区间的最大值,观察上图,我们可以看到我们求f[1][5]的值时已经直接或间接遍历了其区间的所有子区间的f值(否则我们无法求得f[1][4]和f[2][5]),所以我们可以得出动态转移方程:

dp_max [i] [j] = max ( f [i] [j] , max ( dp_max [i] [j-1] , dp_max [i+1] [j] ) )(i != j)

事已至此,我们已经能够得出AC代码

#include <iostream> 
using namespace std;
int a[5100];
int f[5100][5100];
int dp_max[5100][5100];

int main() {
    int n;
    cin>>n;
    for(int i=0;i<n;i++) {
        cin>>a[i];
    }    
    for(int len = 0;len<=n;len++) {
        for(int i=0;i+len<n;i++) {
            if(len==0) {
                f[i][i]=a[i]; 
                dp_max[i][i]=a[i]; 
            }
            else {
                f[i][i+len]= f[i][i+len-1]^f[i+1][i+len];
                dp_max[i][i+len] = max(max(dp_max[i][i+len-1],dp_max[i+1][i+len]),f[i][i+len]);    
            }
        }
    }
    int q;
    cin>>q;
    while(q--) {
        int l,r;
        cin>>l>>r;
        cout<<dp_max[l-1][r-1]<<endl;
    }
    return 0;
}

感想:第一次写题解,身为一个刚刚入门的萌新,可能有跟多不太对的地方,欢迎大家给我指出,不同的同学可以在评论区提问,我有时间会解答的。

猜你喜欢

转载自blog.csdn.net/qq_43305984/article/details/88387002
今日推荐