CF 946D. Timetable 暴力+DP
阿新 • • 發佈:2018-12-24
題意:某星球一週有n天,每天m個小時.每天小A會在該天第一次上課時間p,直到最後一次上課時間q待在學校 共q-p+1小時.
給出課表s,若s[i][j]=='1'代表有上課 否則代表沒課.
問溜掉不超過k節課 使得小A這n天在學校的總時間最小. n,m,k<=500
如果每次只考慮刪一次最多能減小多少,容易找到反例
1 24 2
110000000000000101010101
跑出的結果為21 答案為9.
設d[i][j] 表示前i天翹j次課的最小在校時間 f[i][j]為第i天翹j節課時 該天在校的最短時間.
轉移 d[i][j]=min(d[i-1][p] + f[i][j-p])
給出課表s,若s[i][j]=='1'代表有上課 否則代表沒課.
問溜掉不超過k節課 使得小A這n天在學校的總時間最小. n,m,k<=500
如果每次只考慮刪一次最多能減小多少,容易找到反例
1 24 2
110000000000000101010101
跑出的結果為21 答案為9.
設d[i][j] 表示前i天翹j次課的最小在校時間 f[i][j]為第i天翹j節課時 該天在校的最短時間.
轉移 d[i][j]=min(d[i-1][p] + f[i][j-p])
預處理f[i][j],暴力列舉第i天最後剩下的在校線段[l,r],字首和求出刪除的個數即可.O(n^3).
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N=5e2+5,inf=0x3f3f3f3f; int f[N][N],d[N][N]; int n,m,k,p[N]; char s[N][N]; int main() { // ios::sync_with_stdio(false); // cin.tie(0); cin>>n>>m>>k; memset(d,inf,sizeof(d)); memset(f,inf,sizeof(f)); for(int i=1;i<=n;i++) { scanf("%s",s[i]+1); p[0]=0; for(int j=1;j<=m;j++) p[j]=p[j-1]+(s[i][j]=='1'); f[i][p[m]]=0; for(int l=1;l<=m;l++) { for(int r=l;r<=m;r++) { int tot=p[l-1]+(p[m]-p[r]); if(p[r]-p[l-1]) f[i][tot]=min(f[i][tot],r-l+1); else f[i][tot]=0; } } // for(int j=0;j<=m;j++) // cout<<i<<' '<<j<<' '<<f[i][j]<<'\n'; } for(int j=0;j<=k;j++) d[0][j]=0; for(int i=1;i<=n;i++) for(int j=0;j<=k;j++) for(int p=0;p<=j;p++) d[i][j]=min(d[i][j],d[i-1][p]+f[i][j-p]); cout<<d[n][k]<<'\n'; return 0; }