Educational Codeforces Round 39 D Timetable

500
有n天,每天m个小时,1为有课,0为没课,每天都必须要从第一节课开始待到最后一节课结束,但是可以翘课,最多翘k节,问你最少只需要在学校呆几天.
都是500的数量级
事实上..这是个很容易的dp..
先处理一个zt[i][j],意为第i天如果翘j节课,最少再学校呆多少小时
n^3可以处理出来.
(这个像一个格子移来移去的方法好像好常用啊,没什么好讲的就是..)
然后就是一个简单dp[i][j]
前i天共翘j节课,最少呆多少小时.
也可以n^3处理出来.

#include <iostream>
#include <bitset>
#include <algorithm>
using namespace std;
#define debug(x) std::cerr << #x << " = " << (x) << std::endl
typedef long long LL;
const int MAXN = 5e2+17;
const int INF = 1e9+17;
string a[MAXN];
int nxt[MAXN][MAXN],dp[MAXN][MAXN],zt[MAXN][MAXN],cn[MAXN];
int main(int argc ,char const *argv[])
{
    #ifdef noob
    freopen("Input.txt","r",stdin);freopen("Output.txt","w",stdout);
    #endif        
    int n,m,s;
    cin>>n>>m>>s;
    for (int i = 0; i < n; ++i)
    {
        cin>>a[i];
        int lst = -1;
        for (int j = m-1; j > -1; --j)
        {
            if(a[i][j]=='1')    nxt[i][j]=lst,lst=j,cn[i]++;
            zt[i][j] = INF;
        }
    }
    for (int i = 0; i < n; ++i)
        for (int j = 0; j <= s; ++j)
            dp[i][j]=INF;
    for (int i = 0; i < n; ++i)
    {
        zt[i][cn[i]] = 0;
        for (int l = cn[i]; l > 0; --l)
        {

            if(cn[i]-l>s) break;
            int st=-1,ed=-1;
            for (int k = 0; k < m; ++k)
            {
                if(a[i][k]=='1'&&st==-1)
                    st=k;
            }
            int dur = cn[i]-l;
            for (int k = m-1; k > -1; --k)
            {
                if(a[i][k]=='1')
                {
                    if(dur>0) dur--;
                    else 
                    {
                        ed=k;
                        break;
                    }
                }
            }
            if(st==-1||ed==-1) break;
            zt[i][cn[i]-l] = min(zt[i][cn[i]-l],ed-st+1);
            while(nxt[i][st]!=-1&&nxt[i][ed]!=-1)
            {
                st = nxt[i][st];
                ed = nxt[i][ed];
                zt[i][cn[i]-l] = min(zt[i][cn[i]-l],ed-st+1);
            }
        }
    }
    for (int i = 0; i < n; ++i)
        for (int j = 0; j <= s; ++j)
            for (int k = 0; k <= j; ++k)
                dp[i][j] = min(dp[i-1][j-k]+zt[i][k],dp[i][j]);
    cout<<dp[n-1][s]<<endl;
    return 0;        
}

哇这题500^3 1e8+居然能过,还不太卡,真是没想到..
一开始觉得这个应该过不了,一直在想怎么办..
后来直接锤了个暴力过了..细节还是要注意一下的
最近dp做的有点多(其实不超过一只手T^T)..很多时候其实也没有想清楚,但是就觉得该是这样..完了啊..

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值