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)..很多时候其实也没有想清楚,但是就觉得该是这样..完了啊..