其他分享
首页 > 其他分享> > 牛客小白月赛54

牛客小白月赛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