题目题意

小L有两个长度均为n的数组 a,b以及初始值为0的x。小L现在能操作n次,每一次可以在以下两个规则中任选一个来更新x的值。规则一:将x更新为max(0,x-a[i]);规则二:将x更新为x^b[i]。计算在操作n次后,x的最大值。

题目知识点

动态规划

题目分析

每一次操作都是从规则一、二任选其一,且a、b两数组中的值都是不大于2047的。规则一显而易见,不论操作几次规则一,x的值都不可能大于2047;规则二由按位异或操作可知,不论操作几次规则二,x的值最小为0,最大为2047。综上所述,x的值的范围为[0,2047],既然如此,我们就可以用一个二维数组dp,i用来表示操作到的次数,j用来表示x可能的值。只要dp[i-1][j]为1,那么dp[i][max(0,j-a[i]]=1,dp[i][j^b[i]]=1,那么在操作完之后,我们就可以倒着遍历一遍最后操作,即dp[n][j],只要找到一个不为0的数,那么就可以输出并返回。

有了这样一个思路,我们就可以去写代码了:

#include<bits/stdc++.h>
using namespace std;
int a[2050];
int b[2050];
int dp[2050][2050]={0};
void solve(){
    int n,x=0;
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];  
    for(int i=1;i<=n;i++) cin>>b[i];
    dp[1][max(0,x-a[1])]=1;   //第一次操作采用规则一的值
    dp[1][x^b[1]]=1;          //第一次操作采用规则二的值
    //从第二次操作开始
    for(int i=2;i<=n;i++){ 
        for(int j=0;j<=2047;j++){
            //如果对应j的前一项不为0,那么对应j的规则一、二均有可能取到
            if(dp[i-1][j]){  
                dp[i][max(0,j-a[i])]=1;
                dp[i][j^b[i]]=1;
            }
        }
    }
    //从后往前遍历,只要找到一个不为0的数,即为最大值
    for(int j=2047;j>=0;j--){
        if(dp[n][j]){
            cout<<j;
            return;
        }
    }
}
int main(){
    solve();
}