[Offer收割]编程练习赛3 - 题目3 : 智力竞赛

简介: 智力竞赛  Problem's Link  ---------------------------------------------------------------------------- Mean:  略(中文题).

智力竞赛 

Problem's Link

 ----------------------------------------------------------------------------

Mean: 

略(中文题).

analyse:

比赛中最先想到的是三维dp,但思考后发现可以压缩为二维,状态转移方程:

  • dp[i][j]=min(dp[i][j],dp[i][j-(right+fault)]+right)

其中dp[i][j]表示:

  • 到通过第i关为止,在总共只有j次答题机会的情况下,总共至少需要答对dp[i][j]次

最终answer为dp[n][m].

Time complexity: O(N*M*M)

 

view code

/**
* -----------------------------------------------------------------
* Copyright (c) 2016 crazyacking.All rights reserved.
* -----------------------------------------------------------------
*       Author: crazyacking
*       Date  : 2016-03-30-21.00
*/
#include <queue>
#include <cstdio>
#include <set>
#include <string>
#include <stack>
#include <cmath>
#include <climits>
#include <map>
#include <cstdlib>
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long( LL);
typedef unsigned long long( ULL);
const double eps( 1e-8);

const int N = 1010;
LL a [N ], dp [N ][N ];

int main()
{
    int Cas;
    cin >> Cas;
    while( Cas --)
    {
        int n , m ,s , t;
        cin >>n >> m >>s >> t;
        for( int i = 1; i <=n; ++ i)
        {
            cin >> a [ i ];
            fill( dp [ i ], dp [ i ] +N , INT_MAX);
        }
        fill( dp [ 0 ], dp [ 0 ] +N , 0);
        for( int i = 1; i <=n; ++ i)
        {
            int max_right = a [ i ] /s;
            if( a [ i ] %s) ++ max_right;
            for( int right = 0; right <= max_right; ++ right)
            {
                int dif = a [ i ] -s * right , fault = 0;
                if( dif > 0)
                {
                    if( dif % t) fault = dif / t + 1;
                    else fault = dif / t;
                }
                fault = max( fault , 0);
                for( int chance = m; chance >= right + fault; -- chance)
                    dp [ i ][ chance ] = min( dp [ i ][ chance ], dp [ i - 1 ][ chance -( right + fault )] + right);
            }
        }
        if( dp [n ][ m ] < INT_MAX)
            cout << dp [n ][ m ] << endl;
        else
            cout << "No" << endl;
    }
    return 0;
}
/*

*/


/**< 带注释版 */
/**
* -----------------------------------------------------------------
* Copyright (c) 2016 crazyacking.All rights reserved.
* -----------------------------------------------------------------
*       Author: crazyacking
*       Date  : 2016-03-30-21.00
*/
#include <queue>
#include <cstdio>
#include <set>
#include <string>
#include <stack>
#include <cmath>
#include <climits>
#include <map>
#include <cstdlib>
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long( LL);
typedef unsigned long long( ULL);
const double eps( 1e-8);

const int N = 1010;
LL a [N ], dp [N ][N ];

int main()
{
    int Cas;
    cin >> Cas;
    while( Cas --)
    {
        int n , m ,s , t;
        cin >>n >> m >>s >> t;
        for( int i = 1; i <=n; ++ i)
        {
            cin >> a [ i ];
            fill( dp [ i ], dp [ i ] +N , INT_MAX);
        }
        fill( dp [ 0 ], dp [ 0 ] +N , 0);
        for( int i = 1; i <=n; ++ i) // 到第i关为止
        {
            //对于本关,答对max_right题时,不算错题的分值也能通关
            int max_right = a [ i ] /s;
            if( a [ i ] %s) ++ max_right;
            for( int right = 0; right <= max_right; ++ right)   // 枚举答对的题数
            {
                //答对right题时,需要答错多少题
                int dif = a [ i ] -s * right , fault = 0;
                if( dif > 0)
                {
                    if( dif % t) fault = dif / t + 1;
                    else fault = dif / t;
                }
                fault = max( fault , 0);
                for( int chance = m; chance >= right + fault; -- chance)
                    dp [ i ][ chance ] = min( dp [ i ][ chance ], dp [ i - 1 ][ chance -( right + fault )] + right);
                // dp[i][j] ------到本关为止,若只有chance次答题机会,本关答对了right题,若本关能够通关,到本关为止总共最少需要答对多少题
                // chance-(right+fault) ----- 总共答题机会为chance,本关用了right+fault次,前面所有关只有chance-(right+fault)次机会
            }
        }
        if( dp [n ][ m ] < INT_MAX)
            cout << dp [n ][ m ] << endl;
        else
            cout << "No" << endl;
    }
    return 0;
}
/*

*/

 

目录
相关文章
|
7月前
|
设计模式 消息中间件 存储
第十四届蓝桥杯集训——Queue
第十四届蓝桥杯集训——Queue
41 0
|
机器人
LeetCode 双周赛 106(2023/06/10)两道思维题
往期回顾:[LeetCode 单周赛第 348 场 · 数位 DP 模版学会了吗?](https://mp.weixin.qq.com/s/4aLHpyaLOUEHSaX2X8e5FQ)
89 0
LeetCode 双周赛 106(2023/06/10)两道思维题
|
存储 算法 Python
你离大厂的offer只差这份算法汇总
你离大厂的offer只差这份算法汇总
|
人工智能 算法 C++
【每日算法Day 88】超越妹妹教你如何做这道排序题
【每日算法Day 88】超越妹妹教你如何做这道排序题
|
机器学习/深度学习 人工智能 算法
牛客寒假算法基础集训营1 思考+题解
众所周知,2022年是四年一度的世界杯年,那么当然要整点足球题。本题需要你模拟一次点球大战。 假设对战双方为A和B,则点球大战中双方会按照ABABABABAB方式来罚点球,即两队交替罚点球、各罚五次、A队先罚。点球有罚进和罚不进两种结果,罚中的一方加一分。
100 0
|
机器学习/深度学习 人工智能 BI
蓝桥杯真题31日冲刺国一 | 每日题解报告 第二十七天
大家好 我是泡泡 倒数六天 蓝桥开赛!记得打印准考证!
121 0
蓝桥杯真题31日冲刺国一 | 每日题解报告 第二十七天
|
算法
蓝桥杯真题31日冲刺国一 | 每日题解报告 第三十一天
大家好啊,我是泡泡,今天是我们蓝桥杯打卡最后一天了,后天也就比赛了,明天大家把各种类型的题目复习一下,我中午会发出最后一篇复习文章,希望各位能拿到自己想要的成绩!陪伴大家这么久了,以后也会继续更新优质算法文章等,各位也不要忘记初心,不要为了比赛而比赛,学到东西才是王道!
186 0
|
机器学习/深度学习
蓝桥杯真题31日冲刺国一 | 每日题解报告 第二十八天
大家好,我是泡泡,距离蓝桥杯还有五天,大家一定要坚持下去
125 0
蓝桥杯真题31日冲刺国一 | 每日题解报告 第二十八天
|
人工智能
蓝桥杯真题31日冲刺国一 | 每日题解报告 第二十一天
大家好,我是泡泡,今天有点忙题解来晚了!
81 0
蓝桥杯真题31日冲刺国一 | 每日题解报告 第二十一天
|
Java
蓝桥杯真题31日冲刺国一 | 每日题解报告 第二十二天
大家好,我是泡泡,今天给大家带来五到2020年填空真题和两个打卡题
120 0
蓝桥杯真题31日冲刺国一 | 每日题解报告 第二十二天