背包DP 存在异或条件的状态转移问题

题目链接

分析:有大佬说可以用线性基写,可惜我不会,这是用DP写的

题目明确说明可到达的位置只与能值有关,和下标无关,我们就可以排个序,这样每个数可以转移的区间就是它的所有后缀

我们可以用dp[i][j]表示到达第i个位置,当前耐久度为j是否可行,那就可以根据走或不走两种情况来安排状态转移

也就是说能判断dp[i]j]能不能到达得看存不存在dp[i-1][j]或者dp[i-1][j^a[i].val](注意,两次异或同一数等于没有异或)

另外,排序会存在相等情况,但是题目说过只能到能级比它小的,所以得特判相等的情况

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 const int inf=1<<30;
 4 typedef long long ll;
 5 const double pi=acos(-1);
 6 const int mod=2000120420010122;
 7 const int maxn=3010;
 8 bool dp[maxn][10000];//注意第二维不能够只开到3000 
 9 struct node{
10     int id,val;
11 }a[3010];
12 bool cmp(const node& a,const node& b){
13     return a.val>b.val;
14 }
15 int main(){
16     int n;scanf("%d",&n);
17     for(int i=0;i<n;i++)scanf("%d",&a[i].val),a[i].id=i;
18     sort(a,a+n,cmp);
19     for(int i=0,flag=1;i<n;i++){
20         if(a[i].id==0){
21             flag=0;
22             dp[i][a[i].val]=1;
23             continue;
24         }
25         if(flag) continue;
26         if(a[i].id==n-1){
27             for(int j=10000;j>0;j--){
28                 dp[i][j]=dp[i-1][j^a[i].val];
29                 if(dp[i][j]){
30                     cout<<j<<endl;
31                     return 0;
32                 }
33             }
34         }
35         if(a[i].val==a[i-1].val){
36             for(int j=10000;j>0;j--){
37                 dp[i][j]=dp[i-1][j];
38             }
39         }
40         else {
41             for(int j=10000;j>0;j--){
42                 dp[i][j]=dp[i-1][j]|dp[i-1][j^a[i].val];
43             }
44         }
45     }
46     cout<<"-1\n";
47     return 0;
48 }

 

posted @ 2019-02-27 10:41  清酒令  阅读(377)  评论(0)    收藏  举报