2020HAUT-暑假新生训练1 —— 题解

A题

题意: 在二维坐标系内,给你一个起点,再给你一个终点,外加一个按周期循环的干扰因素-风,问你多少天能到达终点。简单说,每天可以移动一个单位,且要风力方向移动一个单位。

题解:统计在一个周期内每天因风力移动的距离(分为两个方向)和 可以自由移动的次数,当自由移动的次数不小于风力影响后的位置到终点的距离时即可到达,要求最少天数,二分即可。

代码:

#include

using namespace std;
const int maxn = 1e6+1;
int tx[maxn], ty[maxn], n, xs, ys, xe, ye;

bool check(long long mid) {
    long long t = mid / n, f = mid % n;
    if (abs(t * tx[n] + tx[f] + xs - xe) + abs(t * ty[n] + ty[f] + ys - ye) > mid) return true;
    return false;
}

int main() {
    cin >> xs >> ys >> xe >> ye;
    cin >> n; string s; cin >> s;
    for(int i = 1; i <= n; ++ i) {
        tx[i] = tx[i-1];
        ty[i] = ty[i-1];
        if (s[i-1] == 'U') ty[i] ++;
        if (s[i-1] == 'D') ty[i] --;
        if (s[i-1] == 'L') tx[i] --;
        if (s[i-1] == 'R') tx[i] ++;
    }
    long long l = 0, r = 2e18, ans = -1;
    while(l != r) {
        long long mid = l+r >> 1;
        if (check(mid)) l = mid + 1;
        else r = mid, ans = r;
    }
    cout << ans << endl;
    return 0;
}

B题

题意:已经统计出 “00” ,“01” 或 “10”, “11” 的个数,然后根据这些统计构造出字符串。

题解:主要考虑 n0,n1,n2 为零时的情况,还有一个坑点就是 n1 的奇偶性,防止无意间多 ‘01’ (把 ‘0’ 移到最后即可)。

代码:

#include

using namespace std;

int main() {
    int T; cin >> T;
    while(T --) {
        int f = 0;
        int n0, n1, n2; cin >> n0 >> n1 >> n2;
        if (n0) cout << '0';
        for(int i = 1; i <= n0; ++ i) cout << '0';
        if (n0 == 0 && n1) cout << '0'; if (n1 && n1 % 2 == 0) n1 --, f = 1;
        for(int i = 1; i <= n1; ++ i) if (i & 1) cout << '1'; else cout << '0';
        if (n1 % 2 == 0 && n2) cout << '1';
        for(int i = 1; i <= n2; ++ i) cout << '1';
        if (f == 1) cout << '0';
        cout << endl;
    }
    return 0;
}

C题

题意:给你一个字符串,找出下标为等差数列的子序的最大个数。

题解:等差数列这个限制很苛刻的,当子序长度大于2时,子序长度为m的最大个数 <= 子序长度为m-1的最大个数,但子序长度为 1 或 2 时没有任何限制,所以只用找到子序长度为 1 或 2 的最大个数即可。

代码:

#include

using namespace std;

long long cnt[26][26], res[26];

int main() {
    string s; cin >> s;
    long long ans = 0;
    for(int i = 0; i < s.size(); ++ i) {
        for(int j = 0; j < 26; ++ j) {
            cnt[s[i]-'a'][j] += res[j];
            ans = max(ans, cnt[s[i]-'a'][j]);
        }
        res[s[i] - 'a' ] ++;
        ans = max(ans, res[s[i]-'a']);
    }
    cout << ans << endl;
    return 0;
}

D题

题意:给你一个长度为 n 的数组,数组中有值为 -1 的元素,把所有的该种元素用一个数值 x 替换,使得数组中相邻元素的差值最小。

题解:把所有该种元素相邻的元素存入一个数组中,排个序,x = (最大值+最小值) / 2,然后再遍历一遍数组得到最大差值即可。

代码:

#include

using namespace std;

const int maxn = 1e6+1;
long long a[maxn], b[maxn];

int main() {
    int T; cin >> T;
    while(T --) {
        int n; cin >> n; int tot = 0;
        for(int i = 1; i <= n; ++ i) {
            scanf("%lld", &a[i]);
            if (a[i] == -1 && i > 1 && a[i-1] != -1) b[++tot] = a[i-1];
            if (a[i] != -1 && i > 1 && a[i-1] == -1) b[++tot] = a[i];
        }
        sort(b+1, b+tot+1);
        long long m = 0, k = 0;
        if (tot != 0) m = b[1] + b[tot] >> 1;
        for(int i = 1; i <= n; ++ i) {
            if (a[i] == -1) a[i] = m;
            if (i > 1) k = max(k, abs(a[i] - a[i-1]));
        }
        cout << k << " " << m << endl;
    }
    return 0;
}

E题

题意:给你一个01串的长度n,再给01串中1的个数,问怎么构造使得含 1 的子串最多,输出最多的个数。

题解:如果 1 都集中在一起,含 1 的子串是多了,但此时 0 也都集中在一起了,那只含 0 的子串也多了,子串总数是一定的,所以这种贪心是有问题的。我们在把 0 都分散,那只含 0 的子串最少,而子串总数是一定的,所以把 0 分散后统计出只含 0 子串的个数即可。

代码:

#include

using namespace std;

int main() {
    int T; cin >> T;
    while(T --) {
        long long n, m; cin >> n >> m;
        long long sum = n*(n+1) / 2; // 子串总数
        long long t = (n-m) / (m+1), f = (n-m) % (m+1);
        cout << sum - f * (t+1) * (t+2) / 2 - (m+1-f) * t * (t+1) / 2 << endl;
    }
    return 0;
}

F题

题意:在一维坐标系上,给你 n 个区间,让你创造一个区间,若你的区间包裹了 n 个区间中的一些区间,则你的区间获得这些包裹区间的价值,且你的区间每包含一个点价值就 -k 。

题解:线段树模板题,先建一个线段树把所有区间都包裹在内,然后枚举右端点,对左端点进行前缀和处理——右端点之前的点到达右端点的花费,每次枚举都对左端点前缀和进行实时更新,且维护一个最大价值的区间。

代码:

#include

using namespace std;

const int maxn = 2e5+1;
typedef long long LL;

struct node {
    int l, r, id; LL val, lazy;
    node(){}
    node(int l, int r, LL val, LL lazy): l(l), r(r), val(val), lazy(lazy){}
    node(int l, int id, LL val): l(l), id(id), val(val){}
    bool operator< (const node n1) {return r < n1.r;}
    node operator+ (const node n1) {return (val >= n1.val) ? node(l,r,val,0ll) : node(n1.l,n1.r,n1.val,0ll);}
}p[maxn << 2], res(1,0,0ll);
vector<node> g[maxn]; // 以i结尾的区域

void build (int root, int l, int r) {
    if (l == r) {
        p[root] = node(l, r, 0ll, 0ll);
        return ;
    }
    int mid = l+r >> 1;
    build(root<<1,l,mid);
    build(root<<1|1,mid+1,r);
    p[root] = p[root<<1] + p[root<<1|1];
}

void PushDown(int root) {
    if (p[root].lazy) {
        p[root<<1].lazy += p[root].lazy;
        p[root<<1|1].lazy += p[root].lazy;
        p[root<<1].val += p[root].lazy;
        p[root<<1|1].val += p[root].lazy;
        p[root].lazy = 0;
    }
}

void updata (int root, int l, int r, int ul, int ur, int i, LL val) {
    if (l == ul && r == ur) {
        p[root].val += val;
        p[root].r = i;
        p[root].lazy += val;
        return ;
    }
    PushDown(root);
    int mid = l+r >> 1;
    if (mid >= ur) updata(root<<1,l,mid,ul,ur,i,val);
    else if (mid < ul) updata(root<<1|1,mid+1,r,ul,ur,i,val);
    else {
        updata(root<<1,l,mid,ul,mid,i,val);
        updata(root<<1|1,mid+1,r,mid+1,ur,i,val);
    }
    p[root] = p[root<<1] + p[root<<1|1];
}

int main() {
    int n, m = 0; LL k; scanf("%d%lld", &n, &k);
    for(int i = 1; i <= n; ++ i) {
        int l, r; LL val; scanf("%d%d%lld", &l, &r, &val);
        g[r].push_back(node(l, i, val));
        m = max(m, r);
    }
    build(1, 1, m);
    for(int i = 1; i <= m; ++ i) {
        updata(1, 1, m, 1, i, i, -k);
        for(auto j: g[i]) updata(1, 1, m, 1, j.l, i, j.val);
        res = res + p[1];
    }

    if (res.val == 0) {printf("0\n"); return 0;}
    vector<int> ans;
    for(int i = res.l; i <= res.r; ++ i) {
        for(auto j: g[i]) {
            if (j.l >= res.l) ans.push_back(j.id);
        }
    }
    printf("%lld %d %d %d\n", res.val, res.l, res.r, ans.size());
    for(auto i: ans) printf("%d ", i);
    return 0;
}

G题

题意: 给你一个数字t,给一个字符串s。找到满足 a-b2+c3-d4+e5 = t 的最大字典序 abcde ,且a、b、c、d、e都属于s,若无解输出 “no solution” 。(A = 1, B = 2 … Z = 26)

题解:字符串 s 按字典序从大到小排列,dfs一下即可。

代码:

在这里插入代码片#include<bits/stdc++.h>

using namespace std;
int t; string s;
int flag, a[6], b[100];

void dfs(int depth) {
    if (depth == 5) {
        if (a[0] - a[1]*a[1] + a[2]*a[2]*a[2] - a[3]*a[3]*a[3]*a[3] + a[4]*a[4]*a[4]*a[4]*a[4] == t) {
            for(int i = 0; i < 5; ++ i) cout << char(a[i] - 1 + 'A'); cout << endl;
            flag = 1;
        }
        return ;
    }
    for(int i = s.size() - 1; i >= 0; -- i) {
        if (b[i]) continue;
        a[depth] = s[i] - 'A' + 1;
        b[i] = 1;
        dfs(depth+1);
        b[i] = 0;
        if (flag) return ;
    }
}

int main() {
    string ss = "END";
    while(cin >> t >> s) { flag = 0;
        if (t == 0 && s == ss) break;
        for(int i = 0; i < s.size(); ++ i) b[i] = 0;
        sort(s.begin(), s.end());
        dfs(0);
        if (flag == 0) cout << "no solution" << endl;
    }
    return 0;
}

你可能感兴趣的:(题解)