1. 程式人生 > 實用技巧 >2020 計蒜之道 預賽 第三場 石子游戲(簡單)(暴力DP)

2020 計蒜之道 預賽 第三場 石子游戲(簡單)(暴力DP)

石子游戲(簡單)

原題連結

思路:
通過形式容易看出是一道DP。其中異或和的情況只有64種,所以我們可以開一維來記錄當前異或和的狀態。
利用dp[當前位置][異或和][是否選擇當前]來進行狀態轉移。時間複雜度為O(qnm)。

比賽時這道題卡了好久,思路很清晰,但就是跑不出正確結果。後來發現原來忽略了f為-1的情況,初始化預設為0了。。

題解:

#include<bits/stdc++.h>
#define MAX 1005
#define MOD 4294967296
using namespace std;
typedef long long ll;

int a[MAX],v[MAX];
int x[2005];
int dp[MAX][66][2];
int f[2005][66];

int main()
{
	int t,n,m,q,l,r,i,j,k;
	scanf("%d%d%d",&n,&m,&q);
	for(i=0;i<n;i++){
		scanf("%d%d",&a[i],&v[i]);
	}
	for(i=1;i<=q;i++){
		scanf("%d%d%d",&l,&r,&x[i]);
		memset(dp,-1,sizeof(dp));
		dp[l][0][0]=0;
		dp[l][a[l]][1]=v[l];
		for(j=l+1;j<=r;j++){
			for(k=0;k<64;k++){
				dp[j][k][0]=max(dp[j-1][k][0],dp[j-1][k][1]);
				dp[j][k][1]=max(dp[j-1][k^a[j]][0],dp[j-1][k^a[j]][1]);
				if(dp[j][k][1]>-1) dp[j][k][1]+=v[j];
			}
		}
		for(k=0;k<64;k++){
			f[i][k]=max(dp[r][k][0],dp[r][k][1]);
		}
	}
	
//	for(i=1;i<=q;i++){
//		for(j=0;j<64;j++){
//			printf("%d ",f[i][j]);
//		}
//		printf("\n");
//	}
	
	ll ans=0;
	for(k=1;k<=q;k++){
		ll sum=0;
		for(j=0;j<=m-1;j++){
			sum+=f[k][j]*(x[k]^j)%MOD;
			sum%=MOD;
		}
		ans+=(k^sum)%MOD;
		ans%=MOD;
	}	
	printf("%lld\n",ans);
	return 0;
}