Codeforces Round #677 (Div. 3)
F. Zero Remainder Sum || dp
#include <cstdio> #include <algorithm> #include <cstring> using namespace std; const int maxn = 73; int a[maxn][maxn], dp[maxn][maxn][maxn][maxn], d[maxn][maxn]; int main() { int n, m, k; scanf("%d %d %d", &n, &m, &k); for(int i = 1; i <= n; ++i) for(int j = 1; j <= m; ++j) scanf("%d", &a[i][j]); memset(dp, -1, sizeof(dp)); memset(d, -1, sizeof(d)); for(int i = 1; i <= n; ++i) dp[i][0][0][0] = 0; for(int i = 1; i <= n; ++i)//第i行 { for(int j = 0; j < m; ++j)//考虑到第j+1个数是否取 { for(int k1 = 0; k1 <= m/2; ++k1)//取k1个数 { for(int k2 = 0; k2 < k; ++k2)//sum%k等于k2 { if(dp[i][j][k1][k2] == -1) continue; dp[i][j+1][k1][k2] = max(dp[i][j][k1][k2], dp[i][j+1][k1][k2]); dp[i][j+1][k1+1][(k2+a[i][j+1])%k] = max(dp[i][j][k1][k2] + a[i][j+1], dp[i][j+1][k1+1][(k2+a[i][j+1])%k]); } } } } d[0][0] = 0; dp[0][m][0][0] = 0; for(int i = 0; i < n; ++i)//前i行 { for(int j = 0; j < k; j++)//sum%k等于j { for(int k1 = 0; k1 <= m / 2; k1++) { for(int k2 = 0; k2 < k; k2++) { if(d[i][j] == -1) continue; if(dp[i+1][m][k1][k2] == -1) continue; d[i+1][(j+k2)%k] = max(d[i][j] + dp[i+1][m][k1][k2], d[i+1][(j+k2)%k]); } } } } printf("%d\n", d[n][0]); return 0; }
G. Reducing Delivery Cost || 图论最短路
#include <cstdio> #include <vector> #include <queue> #include <cstring> using namespace std; const int maxn = 1005; typedef pair<int, int> P; const int INF = 0x3f3f3f3f; struct edge { int to, cost; edge(int k1, int k2): to{k1}, cost{k2} {} }; int d[maxn], road[maxn][2], dist[maxn][maxn], route[maxn][2]; vector<edge> G[maxn]; priority_queue< P, vector<P>, greater<P> > que; //第一维记录cost,第二维记录to void Dijkstra(int s) { memset(d, INF, sizeof(d)); d[s] = 0; que.push(P(0, s)); while(!que.empty()) { P p = que.top(); que.pop(); int v = p.second; if(d[v] < p.first) continue; //去掉已经被访问过的节点和被更新过的边长 for(unsigned int i = 0; i < G[v].size(); i++) //更新边长 { edge e = G[v][i]; if(d[e.to] > d[v] + e.cost) { d[e.to] = d[v] + e.cost; que.push(P(d[e.to], e.to)); } } } } int main() { int n, m, k, sum = 0; scanf("%d %d %d", &n, &m, &k); for(int i = 1; i <= m; ++i) { int u, v, w; scanf("%d %d %d", &u, &v, &w); G[u].push_back(edge(v, w)); G[v].push_back(edge(u, w)); road[i][0] = u, road[i][1] = v; } for(int i = 1; i <= n; ++i) { Dijkstra(i); for(int j = 1; j <= n; ++j) dist[i][j] = d[j]; } int ans = 0; for(int i = 1; i <= k; ++i) { scanf("%d %d", &route[i][0], &route[i][1]); ans += dist[route[i][0]][route[i][1]]; } int r = 0; for(int i = 1; i <= m; ++i) { sum = 0; for(int j = 1; j <= k; ++j) { int tmp = min(dist[route[j][0]][road[i][0]] + dist[route[j][1]][road[i][1]], dist[route[j][0]][road[i][1]] + dist[route[j][1]][road[i][0]]); sum += max(dist[route[j][0]][route[j][1]] - tmp, 0); } r = max(r, sum); } printf("%d\n", ans - r); return 0; }