Codeforces Round #490 (Div. 3)-赛后补题
思维太僵硬了,我从余数入手,嫩是记录不了每个数要操作多少次。但是如果考虑每个数的贡献,即操作多少次能使得满足条件,就好写了,实际上也是暴力。
#include<bits/stdc++.h> #define ll long long #define P pair<int,int> #define pb push_back #define lson root << 1 #define INF (int)2e9 + 7 #define maxn (int)2e5 + 7 #define rson root << 1 | 1 #define LINF (unsigned long long int)1e18 #define mem(arry, in) memset(arry, in, sizeof(arry)) using namespace std; int n, m, t; int a[maxn], pre[maxn], sum[maxn]; int Find(int x){ return (sum[x] < t ? x : pre[x] = Find(pre[x])); } int main() { ios::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL); cin >> n >> m; for(int i = 0; i < m; i++) pre[i] = (i + 1) % m; t = n / m; ll ans = 0; for(int i = 1; i <= n; i++) { int tp = 0; cin >> tp; int x = Find(tp % m); sum[x]++; a[i] = (x - tp % m + m) % m + tp; ans += a[i] - tp; } cout << ans << endl; for(int i = 1; i <= n; i++) cout << a[i] << " "; cout << endl; return 0; }
E. Reachability from the Capital
题解:先从起点搜索一遍,对不能到达的点加一条从首都到这个点的边(加边操作只能是思维上的,不能真的addedge(st, i),因为后面还有删除边的操作),并标记,假如后加入的边能访问到先前的点,就删除原先对应加的边(说明允许犯错)。
#include<bits/stdc++.h> #define ll long long #define P pair<int,int> #define pb push_back #define lson root << 1 #define INF (int)2e9 + 7 #define maxn (int)5e3 + 7 #define rson root << 1 | 1 #define LINF (unsigned long long int)1e18 #define mem(arry, in) memset(arry, in, sizeof(arry)) using namespace std; int n, m, tot, st; int head[maxn]; bool use[maxn], connect[maxn], link[maxn]; struct node{ int to, next; } g[maxn << 1]; void Inite() { tot = 0; mem(head, -1); } void addedge(int u, int v){ g[tot].to = v; g[tot].next = head[u]; head[u] = tot++; } void DFS(int u){ use[u] = connect[u] = 1; //connect数组表示从首都能到这个点 for(int i = head[u]; i != -1; i = g[i].next){ int v = g[i].to; if(!use[v]){ link[v] = 0; //删除标记 DFS(v); } } } int main() { cin >> n >> m >> st; Inite(); for(int i = 1; i <= m; i++){ int u, v; cin >> u >> v; addedge(u, v); } DFS(st); mem(use, 0); for(int i = 1; i <= n; i++){ if(!connect[i]){ link[i] = 1; DFS(i); mem(use, 0); } } int res = 0; for(int i = 1; i <= n; i++) if(link[i]) res++; cout << res << "\n"; return 0; }
题解:dp[ i ][ j ]:同一爱好的 i 个人分同样的 j 件物品得到的最大价值。
#include<bits/stdc++.h> #define ll long long #define P pair<int,int> #define pb push_back #define lson root << 1 #define INF (int)2e9 + 7 #define maxn (int)1e5 + 7 #define rson root << 1 | 1 #define LINF (unsigned long long int)1e18 #define mem(arry, in) memset(arry, in, sizeof(arry)) using namespace std; int n, k; int cntf[maxn], cnta[maxn], h[15], dp[505][5005]; int main() { cin >> n >> k; int m = n * k; int tp; for(int i = 1; i <= m; i++) cin >> tp, cnta[tp]++; for(int i = 1; i <= n; i++) cin >> tp, cntf[tp]++; for(int i = 1; i <= k; i++) cin >> h[i]; for(int i = 1; i <= n; i++) { for(int j = 1; j <= m; j++){ for(int p = 1; p <= min(j, k); p++) dp[i][j] = max(dp[i][j], dp[i - 1][j - p] + h[p]); } } ll ans = 0; for(int i = 0; i < maxn; i++) if(cntf[i]) ans += (ll)dp[cntf[i]][cnta[i]]; cout << ans << "\n"; return 0; }