【10.31校內測試】【組合數學】【記憶化搜尋/DP】【多起點多終點二進位制拆位Spfa】
阿新 • • 發佈:2018-10-31
Solution
注意取模!!!
Code
#include<bits/stdc++.h> #define mod 1000000007 #define LL long long using namespace std; int n, a, b; LL mpow(LL a, LL b) { LL ans = 1; for(; b; b >>= 1, a = a * a % mod) if(b & 1) ans = ans * a % mod; return ans; } LL fac[200005], inv[200005], l[100005], t[100005]; void init() { fac[0] = 1; inv[0] = 1; for(int i = 1; i <= 200000; i ++) { fac[i] = fac[i - 1] * i % mod; inv[i] = mpow(fac[i], mod - 2); } } LL C(int p, int q) { return fac[p] * inv[q] % mod * inv[p - q] % mod; } int main() { freopen("matrix.in", "r", stdin); freopen("matrix.out", "w", stdout); scanf("%d%d%d", &n, &b, &a); for(int i = 1; i <= n; i ++) scanf("%lld", &l[i]); for(int i = 1; i <= n; i ++) scanf("%lld", &t[i]); LL ans = 0; init(); for(int i = 2; i <= n; i ++) { ans= (ans + b * l[i] % mod * C(n - 2 + n - i, n - 2) % mod * mpow(a, n - i) % mod * mpow(b, n - 2) % mod) % mod; ans = (ans + a * t[i] % mod * C(n - 2 + n - i, n - 2) % mod * mpow(b, n - i) % mod * mpow(a, n - 2) % mod) % mod; } printf("%lld", ans); return 0; }
Solution
二分+DP,二分需要多少組p+q,記憶化搜尋判斷是否可以達到條件。
定義$dp[dep][j][k]$表示當前取到第$dep$個數,還需要j個p,k個q來使滿足條件。(p>q)
每次先儘量放p,剩下中再儘量放q,放q時就有限制,不能取超過$mid-i$,i表示當前取的p的數量。
Code
#include<bits/stdc++.h> using namespace std; int n, a[55], p, q; int sum[55], vis[55][1005][1005], tim, all; bool dfs(int dep, int nump, int numq) { if(nump == 0 && numq == 0) return 1; if(dep == n + 1 || sum[dep] < nump * p + numq * q) return 0; if(vis[dep][nump][numq] == tim) return 0; for(int i = 0; i <= min(nump, a[dep] / p); i ++) if(dfs(dep + 1, nump - i, max(numq - min((a[dep] - p * i) / q, all - i), 0))) return 1; vis[dep][nump][numq] = tim; return 0; } bool check(int mid) { tim ++; all = mid; return dfs(1, mid, mid); } int erfen() { int l = 0, r = sum[1] / (p + q), ans; while(l <= r) { int mid = (l + r) >> 1; if(check(mid)) ans = mid, l = mid + 1; else r = mid - 1; } return ans; } int main() { freopen("pq.in", "r", stdin); freopen("pq.out", "w", stdout); scanf("%d", &n); for(int i = 1; i <= n; i ++) scanf("%d", &a[i]); for(int i = n; i >= 1; i --) sum[i] = sum[i + 1] + a[i]; scanf("%d%d", &p, &q); if(p < q) swap(p, q); int ans = erfen(); printf("%d", ans * (p + q)); return 0; }
Solution
考試最後半小時開始寫QAQ結果發現是做過的題啊??
可是最後Spfa寫錯了!!!我爆哭!!!!
將與1相連的所有點取出來,二進位制分類,分成起點和終點,跑多起點多終點的Spfa,處理出兩兩起點終點間最短路,更新答案即可QAQ
Spfa要判更新的點不能是1!!
Code
#include<bits/stdc++.h> using namespace std; int n, m; struct Node { int v, nex, w; } Edge[200005]; int h[30005], stot = 1; void add(int u, int v, int w) { Edge[++stot] = (Node) {v, h[u], w}; h[u] = stot; } int dis[30005]; int vis[30005], nums, numt, w[30005], t[30005], S[30005], T[30005]; void Spfa1() { queue < int > q; memset(vis, 0, sizeof(vis)); memset(dis, 0x3f3f3f3f, sizeof(dis)); for(int i = 1; i <= nums; i ++) q.push(S[i]), vis[S[i]] = 1, dis[S[i]] = min(dis[S[i]], w[S[i]]); while(!q.empty()) { int u = q.front(); q.pop(); vis[u] = 0; for(int i = h[u]; i; i = Edge[i].nex) { int v = Edge[i].v; if(dis[v] > dis[u] + Edge[i].w && v != 1) { dis[v] = dis[u] + Edge[i].w; if(!vis[v]) { vis[v] = 1; q.push(v); } } } } } void Spfa2() { queue < int > q; memset(vis, 0, sizeof(vis)); memset(dis, 0x3f3f3f3f, sizeof(dis)); for(int i = 1; i <= numt; i ++) q.push(T[i]), vis[T[i]] = 1, dis[T[i]] = min(dis[T[i]], w[T[i]]); while(!q.empty()) { int u = q.front(); q.pop(); vis[u] = 0; for(int i = h[u]; i; i = Edge[i].nex) { int v = Edge[i].v; if(dis[v] > dis[u] + Edge[i].w && v != 1) { dis[v] = dis[u] + Edge[i].w; if(!vis[v]) { vis[v] = 1; q.push(v); } } } } } int tov[30006], tot; int main() { freopen("graph.in", "r", stdin); freopen("graph.out", "w", stdout); scanf("%d%d", &n, &m); for(int i = 1; i <= m; i ++) { int u, v, a, b; scanf("%d%d%d%d", &u, &v, &a, &b); add(u, v, a); add(v, u, b); } int ans = 0x3f3f3f3f; memset(w, 0x3f3f3f3f, sizeof(w)); memset(t, 0x3f3f3f3f, sizeof(t)); for(int i = h[1]; i; i = Edge[i].nex) tov[++tot] = Edge[i].v, w[Edge[i].v] = min(w[Edge[i].v], Edge[i].w), t[Edge[i].v] = min(t[Edge[i].v], Edge[i ^ 1].w); sort(tov + 1, tov + 1 + tot); int M = tov[tot], tt = 0; while(M) { int tmp = (M & 1); nums = 0, numt = 0; for(int i = 1; i <= tot; i ++) if(((tov[i] >> tt) & 1) == tmp) S[++nums] = tov[i]; else T[++numt] = tov[i]; Spfa1(); for(int j = 1; j <= numt; j ++) { ans = min(ans, t[T[j]] + dis[T[j]]); } Spfa2(); for(int j = 1; j <= nums; j ++) { ans = min(ans, t[S[j]] + dis[S[j]]); } M >>= 1, tt ++; } printf("%d", ans); return 0; }