预处理+分组背包
预处理出每天逃x节课的最大收益,然后每天为一组,最多选一个,分组背包计算
分组背包的时候遇到一点小坑,就是状态转移方程 dp[i][j] = max(dp[i][j], dp[i-1][j-c[k]]+v[k]) 写成 dp[i][j] = max(dp[i-1][j], dp[i-1][j-c[k]]+v[k]),后者是错误的, 注意到,前者是在第i组每一次挑选出一个物品,然后与第i天挑出的其他物品比较选择较优的答案, 而后者是第i天挑出一个物品,每次与前i-1天的比较,也就是说没有在第i天里挑出最优的答案,而是选择了一个相对于前i-1天更优的答案(其实一定会比前i-1天更优,因为多拿了一件物品,这是无意义的选择)
#include "iostream" #include "iomanip" #include "string.h" #include "stack" #include "queue" #include "string" #include "vector" #include "set" #include "map" #include "algorithm" #include "stdio.h" #include "math.h" #pragma comment(linker, "/STACK:102400000,102400000") #define bug(x) cout<<x<<" "<<"UUUUU"<<endl; #define mem(a,x) memset(a,x,sizeof(a)) #define step(x) fixed<< setprecision(x)<< #define mp(x,y) make_pair(x,y) #define pb(x) push_back(x) #define ll long long #define endl (" ") #define ft first #define sd second #define lrt (rt<<1) #define rrt (rt<<1|1) using namespace std; const ll mod=1e9+7; const ll INF = 1e18+1LL; const int inf = 1e9+1e8; const double PI=acos(-1.0); const int N=1e5+100; int n, m, k, a[505][505], c[505][505], sum[505], dp[505][505], ans; int main() { scanf("%d %d %d", &n, &m, &k); for(int i=1; i<=n; ++i) { int al = 505, br = -1; for(int j=1; j<=m; ++j) { char c; cin>>c; a[i][j] = c-'0'; sum[j] = sum[j-1] + a[i][j]; if(a[i][j] == 1) { al = min(al, j), br = max(br, j); } } int t = br-al+1; if(al == 505 && br == -1) t=0; ans += t; c[i][sum[m]] = t; for(int l=1; l<=m; ++l) { if(!a[i][l]) continue; for(int r=l; r<=m; ++r) { if(!a[i][r]) continue; int x = sum[m] - (sum[r]-sum[l-1]); c[i][x] = max(c[i][x], t - (r-l+1)); } } } for(ill a, b; void step1() { if(a==0 || b==0) return; else if(a >= 2*b) { a %= 2*b; step1(); } else if(b >= 2*a) { b %= 2*a; step1(); } } int main() { scanf("%lld %lld", &a, &b); step1(); printf("%lld %lld ", a, b); return 0; }nt i=1; i<=n; ++i) { for(int j=0; j<=k; ++j) { for(int l=0; l<=j; ++l) { dp[i][j] = max(dp[i][j], dp[i-1][j-l]+c[i][l]); } } } printf("%d", ans-dp[n][k]); cout<<ans-dp[n][k]<<endl; return 0; }