【Codeforces Round #635 (Div. 2) B】Kana and Dragon Quest game

题目链接

点我呀

翻译

给你一个初始数字x, 你可以对它做两种操作:

  • 1.整除2然后加上10

  • 2.减去10

问你在n次1操作和m次2操作之内, 能不能把数字x变成是小于0的。

题解

n和m都小于30?

这不傻逼题吗?

dp[i][j]表示i次1操作,j次1操作x能到达的最小值。

\(dp[i][j] = min(dp[i-1][j]/2+10,dp[i][j-1] - 10)\)

最后康康 dp 数组里有没有小于等于0的数字就行了。

另解 : 会发现x / 2 + 10这个操作 肯定不能 放在x - 10操作之后的, 假设你这么做了, 那么两个操作之后, x
就变成(x - 10) / 2 + 10也即x/2 + 5,但是如果你先做x / 2 + 10的话, 两个操作之后, x就会变成x/2, 显然
更优秀, 所以你正确的做法应该是, 先让x一直做x/2 + 10这个操作, 然后再一直做x-10这个操作。

理解:如果有"21"这样的情况, 交换成"12"肯定更好。所以最后就变成"111122222"这样的操作了。

代码

#include<bits/stdc++.h>
#define ll long long
#define rei(x) scanf("%d",&x)
#define rel(x) scanf("%I64d",&x)
#define rep1(i,a,b) for (int i = a;i <= b;i++)
#define rep2(i,a,b) for (int i = a;i >= b;i--)
using namespace std;

const int N = 30;

int T,x,n,m;
int dp[N+5][N+50];

int main(){
    #ifdef LOCAL_DEFINE
        freopen("D:\\rush.txt","r",stdin);
    #endif
    ios::sync_with_stdio(0),cin.tie(0);
    rei(T);
    while(T--){
        rei(x);rei(n);rei(m);
        rep1(i,0,N)
            rep1(j,0,N)
                dp[i][j] = x+1;
        rep1(i,0,n)
            rep1(j,0,m)
                if (i==0 && j == 0){
                    dp[i][j] = x;
                }else{
                    if (i>0){
                        dp[i][j] = min(dp[i][j],dp[i-1][j]/2 + 10);
                    }
                    if (j>0){
                        dp[i][j] = min(dp[i][j],dp[i][j-1] - 10);
                    }
                }
        bool ok = false;
        rep1(i,0,n)
            rep1(j,0,m)
                if (dp[i][j]<=0){
                    ok = true;
                    break;
                }
        if (ok){
            cout<<"YES"<<endl;
        }else{
            cout<<"NO"<<endl;
        }
    }
    return 0;
}
posted @ 2020-06-14 10:17  AWCXV  阅读(157)  评论(0编辑  收藏  举报