AB 时间太多久远 不记得了 - -
这次来补题 - - C和D
刚学了拓扑排序 迫不及待来补这个C 挺不错的题目
不过这里有个坑点就是 a b 如果b是a的前缀 这样是无解的 比如 abc ab 是不满足字典序的 特判一下
然后记录下拓扑排序代码 是dfs的姿势 入度出度那两种姿势也挺好的
入度的是拓扑序 u->v邻接表/链式前向星 记录v的入度 然后0入度的进队列 不断拆边
入度的是逆拓扑序 u->v邻接表 u.size()就是u的出度 其实链式前向星v->u记录u的出度也是可以的 然后0出度的进队列 不断拆边
// // Created by TaoSama on 2015-05-18 // Copyright (c) 2015 TaoSama. All rights reserved. // #include <algorithm> #include <cctype> #include <cmath> #include <cstdio> #include <cstdlib> #include <cstring> #include <iomanip> #include <iostream> #include <map> #include <queue> #include <string> #include <set> #include <vector> using namespace std; const int INF = 0x3f3f3f3f; const int MOD = 1e9 + 7; const int N = 1e5 + 10; string a[105], ans; int n, c[26]; vector<int> G[26]; bool dfs(int u) { c[u] = -1; for(int i = 0; i < G[u].size(); ++i) { int &v = G[u][i]; if(c[v] < 0 || !c[v] && !dfs(v)) return false; } c[u] = 1; ans = (char)(u + 'a') + ans; return true; } bool toposort() { ans.clear(); memset(c, 0, sizeof c); for(int i = 0; i < 26; ++i) if(!c[i] && !dfs(i)) return false; return true; } int main() { #ifdef LOCAL freopen("in.txt", "r", stdin); // freopen("out.txt","w",stdout); #endif ios_base::sync_with_stdio(0); while(cin >> n) { for(int i = 0; i < 26; ++i) G[i].clear(); for(int i = 1; i <= n; ++i) cin >> a[i]; bool ok = true; for(int i = 1; i < n; ++i) { bool prefix = true; for(int j = 0; j < min(a[i].size(), a[i + 1].size()); ++j) { if(a[i][j] != a[i + 1][j]) { prefix = false; G[a[i][j] - 'a'].push_back(a[i + 1][j] - 'a'); break; } } if(prefix && a[i].size() > a[i + 1].size()) { ok = false; break; } } if(!ok || !toposort()) cout << "Impossible\n"; else cout << ans << '\n'; } return 0; }
Fox Ciel is playing a game. In this game there is an infinite long tape with cells indexed by integers (positive, negative and zero). At the beginning she is standing at the cell 0.
There are also n cards, each card has 2 attributes: length li and cost ci. If she pays ci dollars then she can apply i-th card. After applying i-th card she becomes able to make jumps of length li, i. e. from cell x to cell (x - li) or cell (x + li).
She wants to be able to jump to any cell on the tape (possibly, visiting some intermediate cells). For achieving this goal, she wants to buy some cards, paying as little money as possible.
If this is possible, calculate the minimal cost.
The first line contains an integer n (1 ≤ n ≤ 300), number of cards.
The second line contains n numbers li (1 ≤ li ≤ 109), the jump lengths of cards.
The third line contains n numbers ci (1 ≤ ci ≤ 105), the costs of cards.
If it is impossible to buy some cards and become able to jump to any cell, output -1. Otherwise output the minimal cost of buying such set of cards.
3 100 99 9900 1 1 1
2
5 10 20 30 40 50 1 1 1 1 1
-1
7 15015 10010 6006 4290 2730 2310 1 1 1 1 1 1 1 10
6
8 4264 4921 6321 6984 2316 8432 6120 1026 4264 4921 6321 6984 2316 8432 6120 1026
7237
这个题也很好棒啦~ 由于l[i] <= 1e9 l[i]不会有超过2000个的约数 然后就可以用map + dp来暴力了
dp[i][j] := 公约数为i 最小花费是j
然后就很自然了 - - 好棒dp还可以这么写
// // Created by TaoSama on 2015-05-18 // Copyright (c) 2015 TaoSama. All rights reserved. // #include <algorithm> #include <cctype> #include <cmath> #include <cstdio> #include <cstdlib> #include <cstring> #include <iomanip> #include <iostream> #include <map> #include <queue> #include <string> #include <set> #include <vector> using namespace std; const int INF = 0x3f3f3f3f; const int MOD = 1e9 + 7; const int N = 1e5 + 10; int n, l[305], c[305]; map<int, int> dp; //dp[i][j] 公约数first 的最小花费second int main() { #ifdef LOCAL freopen("in.txt", "r", stdin); // freopen("out.txt","w",stdout); #endif ios_base::sync_with_stdio(0); while(cin >> n) { for(int i = 1; i <= n; ++i) cin >> l[i]; for(int i = 1; i <= n; ++i) cin >> c[i]; dp.clear(); dp[0] = 0; for(int i = 1; i <= n; ++i) { for(auto it = dp.begin(); it != dp.end(); ++it) { int t = __gcd(l[i], it->first); if(dp.count(t)) dp[t] = min(dp[t], it->second + c[i]); else dp[t] = it->second + c[i]; } } if(dp.count(1)) cout << dp[1] << '\n'; else cout << "-1\n"; } return 0; }