2018南京网络赛B
有三种操作,第一种把+v,第二种-v,第三种*-1。现在先手的会让最后的值最大,后手的让最后的值最小。
所有操作后的值在区间[-100,100]内,问最后的值是多少。
因为所有的值只有200种可能性,所有每个操作之后最多可能也只有200种值。
那么记忆化搜索把每个操作之后的状态存下来就避免了暴力搜索所有的情况。
#include <bits/stdc++.h> #define pb push_back #define mp make_pair #define x first #define y second #define lson l,mid,rt<<1 #define rson mid+1,r,rt<<1|1 #define up rt,rt<<1,rt<<1|1 #define mem(x) memset(x,0,sizeof(x)) #define mem1(x) memset(x,-1,sizeof(x)) #define LMissher using namespace std; typedef long long ll; typedef double db; const int M = 1e5+7; const double pi = acos(-1); const int inf = 2147483647; const int mod = 1e9+7; int n,m,k,l; int dp[1007][207],a[1007][5];//因为数永远在-100~100,所有每个操作只可能有200个状态 //所以总的搜索次数是200*n,n是1000,复杂度为O(跑得飞快) int dfs(int i,int mon){ if(i>n) return mon-100;//如果已经把n个操作做完 if(dp[i][mon]!=inf) return dp[i][mon];//如果这个状态已经有了直接返回 if(i%2!=0){//第一个人操作使数最大 int tmp=mon-100,ans=-100; if(a[i][1]!=0){ int cnt=min(tmp+a[i][1],100);//最大值不超过100 ans=max(ans,dfs(i+1,cnt+100));//答案由下一个状态转移而来 } if(a[i][2]!=0){ int cnt=max(tmp-a[i][2],-100);//最小值不小于-100 ans=max(ans,dfs(i+1,cnt+100)); } if(a[i][3]!=0){ ans=max(ans,dfs(i+1,tmp*-1+100)); } dp[i][mon]=ans;//这个状态已经确定答案,记忆下来 return ans; } else{ int tmp=mon-100,ans=100; if(a[i][1]!=0){ int cnt=min(tmp+a[i][1],100); ans=min(ans,dfs(i+1,cnt+100)); } if(a[i][2]!=0){ int cnt=max(tmp-a[i][2],-100); ans=min(ans,dfs(i+1,cnt+100)); } if(a[i][3]!=0){ ans=min(ans,dfs(i+1,tmp*-1+100)); } dp[i][mon]=ans; return ans; } } int main(){ #ifdef LMissher freopen("1.in","r",stdin); freopen("1.out","w",stdout); #endif scanf("%d%d%d%d",&n,&m,&k,&l); for(int i=1;i<=n;i++) for(int j=0;j<=201;j++) dp[i][j]=inf;//搜索初始状态 for(int i=1;i<=n;i++) scanf("%d%d%d",&a[i][1],&a[i][2],&a[i][3]); int ans=dfs(1,m+100);//把负数变成可以用下标表示 if(ans>=k) printf("Good Ending\n"); else if(ans<=l) printf("Bad Ending\n"); else printf("Normal Ending\n"); return 0; }

浙公网安备 33010602011771号