https://ac.nowcoder.com/acm/contest/38457#question
题意不用说,因为是中文,自己看就得了
感觉这次比上回难点
EF 待补
最容易想到的思路就是拿个堆,每次找最大的两个数相加。但是这么做复杂度暴了(我不会算)。
考虑优化一下。先排个序,每次贪心的选最大的两个相加(为什么是两个呢,因为少的肯定比多的优,先加的比较少的话,就可以再多加几次)。这个过程就相当于从后往前求和,前缀和优化一下就行(后缀和也行,更方便)。
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int mod = 1e7 + 7, N = 2e5 + 5; ll a[N], sum[N]; void solve () { int n; ll ans = 0; scanf ("%d", &n); for (int i = 1; i <= n; i ++) cin >> a[i]; sort (a + 1, a + n + 1); for (int i = 1; i <= n; i ++) sum[i] = sum[i-1] + a[i]; for (int i = 1; i < n; i ++) { ll dx = sum[n] - sum[n-i-1]; if (dx < 0) break; ans += dx; } cout << max(0ll, ans % mod) << endl; } int main () { int t; cin >> t; while (t --) { solve (); } }
题目要求在不取满 \(m\) 个的情况下尽可能大,易得最优可能是取 \(m-1\) 个
容易想到的思路就是枚举那个不选的点,然后比较选取权值最小的去掉。
如图:
权值的计算涉及区间覆盖,可以利用差分来做
#include <bits/stdc++.h> #define int long long using namespace std; const int N = 1e6 + 5; int n, m, sum[N]; signed main () { cin >> n >> m; int ans = 0, tot = 0; for (int i = 1; i <= n; i++) { int l, r, s; cin >> l >> r >> s; sum[r+1] -= s, sum[l] += s; tot += s; } for (int i = 1; i <= m; i ++) { sum[i] += sum[i-1]; //cout << sum[i] << ' '; ans = max (ans, tot - sum[i]); } cout << ans << endl; } //不取某点,枚举该点
可以先把时间转化为具体的值(统一化单位为 分),然后问题就变为,有 \(n\) 个区间,\(m\) 次询问某点是否在区间内。对于 \(n\) 个区间可以先进行排序,合并等处理,然后二分查找,时间复杂度就可以由 \(O(nq)\) 变为 \(O(qlogn)\)
要读入优化,不然会超时
注意如果输入的左端点大于右端点就代表跨了 天 ,故要划分为两个区间
#include <bits/stdc++.h> #define int long long using namespace std; typedef pair<int, int> pii; const int N = 1e3 + 5, M = 2e6 + 5; int n, m, h, q; vector <int> l, r; inline int read() { int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar(); return x*f; } signed main () { n = read(), h = read(), m = read(), q = read(); int maxn = h*m; for (int i = 0; i < n; i ++) { int a, b, c, d; a = read(), b = read(), c = read(), d = read(); a = a*m + b, c = c*m + d; if (a > c) { l.push_back (a), r.push_back (maxn); l.push_back (0), r.push_back (c); } else l.push_back(a), r.push_back(c); } sort (l.begin(), l.end()), sort (r.begin(), r.end()); l.erase (unique(l.begin(), l.end()), l.end()); r.erase (unique(r.begin(), r.end()), r.end()); int sz = l.size(); // for (int i = 0; i < sz; i ++) // cout << l[i] << ' ' << r[i] << endl; while (q --) { int x, y; x = read(), y = read(); x = x*m + y; //cout << x << " "; int j = lower_bound (r.begin(), r.end(), x) - r.begin(); //cout << j << endl; if (j == sz) printf("Yes\n"); else { if (l[j] <= x || r[j] == x) printf("No\n"); else printf("Yes\n"); } } } //O(qlogn)
可以把每一个单词都看成一个点,两点之间能连边的条件为有且仅有一个字符不同。那么就可以按照这个思路去构造图,然后跑最短路即可。
注意路径记录(有人不会QAQ)
#include <bits/stdc++.h> using namespace std; typedef pair<int, int> pii; const int N = 2005; int n, m, dis[N], path[N]; string s[N]; bool vis[N]; int a[N][N]; bool match (string a, string b) { int dif = 0; for (int i = 0; i < m; i ++) if (a[i] != b[i]) dif ++; if (dif == 1) return true; return false; } int dijkstra () { for (int i = 0; i <= n; i ++) { dis[i] = a[0][i]; vis[i] = false; path[i] = -1; } vis[0] = true; dis[0] = 0; for (int i = 0; i <= n; i ++) { int p, minn = 0x3f3f3f3f; for (int j = 0; j <= n; j ++) { if (!vis[j] && dis[j] < minn) { p = j; minn = dis[j]; } } vis[p] = true; for (int j = 0; j <= n; j++) { if (dis[p] + a[p][j] < dis[j]) { dis[j] = minn + a[p][j]; path[j] = p; } } } if (dis[n] == 0x3f3f3f3f) return -1; return dis[n]-1; } void print () { stack<int> q; int j = n; while (path[j] != -1) { q.push(j), j = path[j]; } q.push (j); cout << s[0] << endl; while (!q.empty()) { cout << s[q.top()] << endl; q.pop(); } } int main () { memset (a, 0x3f, sizeof a); memset (path, -1, sizeof path); cin >> n >> m; for (int i = 1; i <= n; i ++) cin >> s[i]; n ++; cin >> s[0] >> s[n]; if (s[0] == s[n]) { cout << 0 << endl; cout << s[0] << endl << s[n] << endl; return 0; } for (int i = 0; i <= n; i ++) { a[i][i] = 0; for (int j = i + 1; j <= n; j++) { if (s[i] != s[j] && match(s[i], s[j])) a[i][j] = a[j][i] = 1; } } int t = dijkstra (); cout << t << endl; if (t != -1) { print(); } } //图论 //能转化的建一条边,跑最短路