牛客小白月赛54
作者:互联网
牛客小白月赛54
https://ac.nowcoder.com/acm/contest/38457#question
题意不用说,因为是中文,自己看就得了
感觉这次比上回难点
EF 待补
A - Sum
最容易想到的思路就是拿个堆,每次找最大的两个数相加。但是这么做复杂度暴了(我不会算)。
考虑优化一下。先排个序,每次贪心的选最大的两个相加(为什么是两个呢,因为少的肯定比多的优,先加的比较少的话,就可以再多加几次)。这个过程就相当于从后往前求和,前缀和优化一下就行(后缀和也行,更方便)。
#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 ();
}
}
B - Gaming
题目要求在不取满 \(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;
}
//不取某点,枚举该点
C - School
可以先把时间转化为具体的值(统一化单位为 分),然后问题就变为,有 \(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)
D - Word
可以把每一个单词都看成一个点,两点之间能连边的条件为有且仅有一个字符不同。那么就可以按照这个思路去构造图,然后跑最短路即可。
注意路径记录(有人不会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();
}
}
//图论
//能转化的建一条边,跑最短路
E - Slash
F - Traveling
标签:ch,end,int,54,back,long,牛客,小白月赛,push 来源: https://www.cnblogs.com/CTing/p/16581524.html