P1095 守望者的逃离
先用了贪心吧这个题 A 了,然后来考虑 dp 怎么做
先说贪心,其中 s1 表示走路的距离, s2 表示闪现了多远
s2 相当于只闪现,没蓝了就原地回蓝
但 s1 是两者兼备的,如果闪现的距离更远,就将 s1 覆盖为 s2
#include<iostream> #include<cstdio> #include<cstring> //#define t time #define NUM 100000010 #define ll long long using namespace std; ll m,s,t; ll s1,s2,ans; signed main(){ ios::sync_with_stdio( false ); cin >> m >> s >> t; while( s1 < s ){ s1 += 17; if( m >= 10 ){ s2 += 60; m -= 10; }else m += 4; s1 = max(s1,s2); ans++; if( ans >= t ) break; } if( s1 >= s ) printf( "Yes\n%lld",ans ); else printf( "No\n%lld",s1 ); return 0; }
上面是贪心的做法,dp 的话其实跟这个差不多
开一个 dp[i] 存第 i 秒的最远距离,
然后相当于贪心了,如果能闪现就闪现,跑步更优就跑步
还有一种做法,是看题解了,正儿八经的 dp
但是时间会超,想看就看看吧
设dp[i] [j] [1/0] 在第i秒时,魔法值为j, 0代表是由前一秒恢复得到的j,1代表不是恢复得到的j 则dp[i] [j] [0/1] 代表在第i秒时,魔法值为j, 是否是由恢复得到的j 所能跑到的最远距离 然后我们可以推出状态转移方程 先假设使用跳跃技能 dp[i] [j] [1]=max(dp[i-1] [j+10] [1]+60,dp[i-1] [j+10] [0]+60); 第i秒时魔法为j并且不是恢复的来的j(那么只能是由上一次消耗得来) 所以为第i-1秒法力值为j+10秒时候0/1两个状态得来, 并且此种情况的条件为j+10<=m+1 为什么是m+1可以好好想一想 然后就是假设不用跳跃技能的最大值: dp[i] [j] [1]=max(dp[i] [j] [1],dp[i-1] [j][1]+17); dp[i] [j] [1]=max(dp[i] [j] [1],dp[i-1][j] [0] +17); 然后就是0的情况,是由恢复法力得来的 j 那么状态转移方程式为: if(j>=4) dp[i] [j] [0]=max(dp[i-1][j-4] [1],dp[i-1] [j-4] [0]); 但是由于空间相当的大,我们要换成滚动数组 但是不开O2还是会T两个点
1 #include<bits/stdc++.h> 2 using namespace std; 3 int M,S,T,MAXN; 4 int t; 5 //dp[i][j][1/0] 在第i秒 ,魔法值为j 0代表是否是恢复得到的j,1代表不是恢复得到的j 是否跑的最远距离 6 int dp[2][1010][2]; 7 8 int main(){ 9 cin>>M>>S>>T; //输入 10 for(int i=1;i<=T;i++){ 11 for(int j=M;j>=1;j--){ 12 if(j+10<=M+1) dp[i%2][j][1]=max(dp[(i-1)%2][j+10][1]+60,dp[(i-1)%2][j+10][0]+60); 13 dp[i%2][j][1]=max(dp[i%2][j][1],dp[(i-1)%2][j][1]+17); 14 dp[i%2][j][1]=max(dp[i%2][j][1],dp[(i-1)%2][j][0]+17); 15 if(j>=4) dp[i%2][j][0]=max(dp[(i-1)%2][j-4][1],dp[(i-1)%2][j-4][0]); 16 MAXN=max(MAXN,dp[i%2][j][1]); 17 MAXN=max(MAXN,dp[i%2][j][0]); 18 if(MAXN>=S&&t==0) t=i; 19 } 20 } 21 22 if(MAXN<S){ 23 cout<<"No"<<endl<<MAXN; 24 } 25 else{ 26 cout<<"Yes"<<endl; 27 cout<<t; 28 } 29 }