21.11.12模擬 P3486 [POI2009]KON-Ticket Inspector
阿新 • • 發佈:2021-11-13
看到資料,顯然很可能是\(n^2k\)的暴力DP,題目要求查詢不同的人,就是個二維字首和的過程。加入在i站查,上次查是j站,那麼就是在j+1 ~ i上站,i+1 ~ n下站的人數,二維字首和即可
注意,第i站是先下車再查詢,
\[f[i][k]表示第i站查第k次的最大價值, \\ f[i][k]=max(f[j][k-1]+val), 0 \le j < i \]題目要求輸出最小字典序,我們開個pre記錄即可。記錄能達到最大價值查k次的最小i,再往前找答案,這樣的字典序是最小的
const int N = 607; int f[N][57], pre[N][57]; int a[N][N]; int n, K, ans[N]; inline int sum(int x2, int y2, int x1, int y1) { return a[x2][y2] + a[x1-1][y1-1] - a[x1-1][y2] - a[x2][y1-1]; } int main() { freopen("ticket.in", "r", stdin); freopen("ticket.out", "w", stdout); read(n); read(K); rep(i, 1, n) { rep(j, i+1, n) { read(a[i][j]); } } rep(i, 1, n) { rep(j, 1, n) { a[i][j] += a[i - 1][j] + a[i][j - 1] - a[i - 1][j - 1]; } } memset(f, 0xcf, sizeof f); f[0][0] = 0; int mx(0),last(0); rep(k, 1, K) { rep(i, 1, n - 1) { rep(j, 0, i - 1) { int val = sum(i, n, j + 1, i + 1); if(f[i][k] < f[j][k - 1] + val) { f[i][k] = f[j][k - 1] + val; pre[i][k] = j; } } if(k == K && f[i][k] > mx) { mx = f[i][k]; last= i; } } } int j(last); int t(K); do { ans[t] = j; j = pre[j][t]; }while(t--); rep(i, 1, K) { out(ans[i], ' '); } putchar('\n'); return 0; }
本文來自部落格園,作者:{2519},轉載請註明原文連結:https://www.cnblogs.com/QQ2519/p/15547297.html