AtCoder Beginner Contest 366 A~F

A.Election 2(思维)

题意:

A t C o d e r AtCoder AtCoder 市正在举行市长选举。候选人是高桥和青木。
N N N 张有效选票投给两位候选人中的任何一位,目前正在进行计票。这里, N N N 是奇数。
目前的计票结果是:高桥 T T T 票,青木 A A A 票。
请判断此时选举结果是否已经确定。

分析:

我们计算票数少的加上剩下的所有票能不能超过票数多的即可。

代码:

#include <bits/stdc++.h>

using namespace std;

int main() {
    int a, b, c;
    cin >> a >> b >> c;
    if (min(b, c) + a - b - c > max(b, c))
        cout << "No" << endl;
    else
        cout << "Yes" << endl;
    return 0;
}

B. Vertical Writing(模拟)

题意:

给你一个横向书写的文本。将其转换为竖写,用 * 填充空格。

给你 N N N 个由小写英文字母组成的字符串 S 1 , S 2 , … , S N S_1, S_2, \dots, S_N S1,S2,,SN 。设 M M M 为这些字符串的最大长度。

打印 M M M 个满足以下条件的字符串 T 1 , T 2 , … , T M T_1, T_2, \dots, T_M T1,T2,,TM

  • 每个 T i T_i Ti 由小写英文字母和 * 组成。
  • 每个 T i T_i Ti 不以 * 结尾。
  • 每个 1 ≤ i ≤ N 1 \leq i \leq N 1iN 都满足以下条件:
    • 对于每个 1 ≤ j ≤ ∣ S i ∣ 1 \leq j \leq |S_i| 1jSi T j T_j Tj ( N − i + 1 ) (N-i+1) (Ni+1) 个字符存在, T 1 , T 2 , … , T ∣ S i ∣ T_1, T_2, \dots, T_{|S_i|} T1,T2,,TSi ( N − i + 1 ) (N-i+1) (Ni+1) 个字符按此顺序连接等于 S i S_i Si
    • 对于每一个 ∣ S i ∣ + 1 ≤ j ≤ M |S_i| + 1 \leq j \leq M Si+1jM T j T_j Tj ( N − i + 1 ) (N-i+1) (Ni+1) 个字符要么不存在,要么是 *

这里, ∣ S i ∣ |S_i| Si 表示字符串 S i S_i Si 的长度。

分析:

我们将 n n n个字符串顺时针旋转 90 90 90度,然后对于每一行,从右往左,一旦碰到字符,后续再碰到 时,替换成*即可。

代码:

#include <bits/stdc++.h>

using namespace std;
char tmp[105][105];

int main() {
    int n, m = -1;
    cin >> n;
    for (int i = 0; i < n; i++) {
        string s;
        int l;
        cin >> s;
        l = s.length();
        m = max(m, l);
        for (int j = 0; j < l; j++)
            tmp[i][j] = s[j];
    }
    for (int i = 0; i < m; i++) {
        string s = "";
        for (int j = n - 1; j >= 0; j--) {
            if (tmp[j][i])
                s += tmp[j][i];
            else
                s += '*';
        }
        while (s[s.length() - 1] == '*')
            s = s.substr(0, s.length() - 1);
        cout << s << endl;
    }
    return 0;
}

C.Balls and Bag Query(数据结构)

题意:

你有一个空袋子。给你 Q Q Q 个查询,必须按顺序处理。

有三种查询。

  • 1 x :将一个写有整数 x x x 的球放入袋子中。
  • 2 x : 从袋子中取出一个写有整数 x x x 的球并丢弃。当给出这个查询时,可以保证袋子中有一个写着整数 x x x 的球。
  • 3 : 打印袋中写有不同整数的球的个数。

分析:

m a p map map维护一下各个数字球的个数,当 m a p [ x ] = 0 map[x]=0 map[x]=0时移除该元素,询问就是 m a p . s i z e ( ) map.size() map.size()

代码:

#include <bits/stdc++.h>

using namespace std;

int main() {
    int q;
    cin >> q;
    map<int, int> tmp;
    while (q--) {
        int op;
        cin >> op;
        if (op == 1) {
            int x;
            cin >> x;
            tmp[x]++;
        } else if (op == 2) {
            int x;
            cin >> x;
            tmp[x]--;
            if (tmp[x] == 0)
                tmp.erase(x);
        } else {
            cout << tmp.size() << endl;
        }
    }
    return 0;
}

D.Cuboid Sum Query (思维)

题意:

给你一个正整数 N N N 和一个整数 A x , y , z A_{x,y,z} Ax,y,z ,每个整数 ( x , y , z ) (x, y, z) (x,y,z) 的三元组都是 1 ≤ x , y , z ≤ N 1 \leq x, y, z \leq N 1x,y,zN

你将得到以下格式的 Q Q Q 个查询,必须按顺序处理。

对于 i i i 查询 ( 1 ≤ i ≤ Q ) (1 \leq i \leq Q) (1iQ) ,我们会给你一个由整数 ( L x i , R x i , L y i , R y i , L z i , R z i ) (Lx_i, Rx_i, Ly_i, Ry_i, Lz_i, Rz_i) (Lxi,Rxi,Lyi,Ryi,Lzi,Rzi) 组成的元组 1 ≤ L x i ≤ R x i ≤ N 1 \leq Lx_i \leq Rx_i \leq N 1LxiRxiN 1 ≤ L y i ≤ R y i ≤ N 1 \leq Ly_i \leq Ry_i \leq N 1LyiRyiN 1 ≤ L z i ≤ R z i ≤ N 1 \leq Lz_i \leq Rz_i \leq N 1LziRziN 。查找:

∑ x = L x i R x i ∑ y = L y i R y i ∑ z = L z i R z i A x , y , z \displaystyle{\sum_{x=Lx_i}^{Rx_i} \sum_{y=Ly_i}^{Ry_i} \sum_{z=Lz_i}^{Rz_i} A_{x,y,z}} x=LxiRxiy=LyiRyiz=LziRziAx,y,z .

分析:

我们令 S i , j , k = ∑ x = 1 i − 1 ∑ y = 1 j − 1 ∑ z = 1 k − 1 A x , y , z S_{i,j,k}=\sum\limits_{x=1}^{i-1} \sum\limits_{y=1}^{j-1}\sum\limits_{z=1}^{k-1}A_{x,y,z} Si,j,k=x=1i1y=1j1z=1k1Ax,y,z 1 ≤ i , j , k ≤ N + 1 1 \leq i,j,k \leq N+1 1i,j,kN+1 。(如果 i i i j j j k k k 0 0 0 ,我们定义为 S i , k , k = 0 S_{i,k,k}=0 Si,k,k=0 )。

那么 ∑ x = L x i R x i ∑ y = L y i R y i ∑ z = L z i R z i A x , y , z = S R x i + 1 , R y i + 1 , R z i + 1 − S L x i , R x i + 1 , R z i + 1 − S R x i + 1 , L y i , R z i + 1 − S R x i + 1 , R y i + 1 , L z i + S L x i , L y i , R z i + 1 + S L x i , R y i + 1 , L z i + S R x i + 1 , L y i , L z i − S L x i , L y i , L z i \sum\limits_{x=Lx_i}^{Rx_i} \sum\limits_{y=Ly_i}^{Ry_i} \sum\limits_{z=Lz_i}^{Rz_i} A_{x,y,z}=S_{Rx_i+1,Ry_i+1,Rz_i+1}-S_{Lx_i,Rx_i+1,Rz_i+1}-S_{Rx_i+1,Ly_i,Rz_i+1}-S_{Rx_i+1,Ry_i+1,Lz_i}+S_{Lx_i,Ly_i,Rz_i+1}+S_{Lx_i,Ry_i+1,Lz_i}+S_{Rx_i+1,Ly_i,Lz_i}-S_{Lx_i,Ly_i,Lz_i} x=LxiRxiy=LyiRyiz=LziRziAx,y,z=SRxi+1,Ryi+1,Rzi+1SLxi,Rxi+1,Rzi+1SRxi+1,Lyi,Rzi+1SRxi+1,Ryi+1,Lzi+SLxi,Lyi,Rzi+1+SLxi,Ryi+1,Lzi+SRxi+1,Lyi,LziSLxi,Lyi,Lzi 成立。

所以,如果我们能快速计算 S S S ,那么每个查询都能在恒定的时间内得到回答。

事实上,根据 S i , j , k = S i − 1 , j , k + S i , j − 1 , k + S i , j , k − 1 − S i − 1 , j − 1 , k − S i − 1 , j , k − 1 − S i , j − 1 , k − 1 + S i − 1 , j − 1 , k − 1 + A i − 1 , j − 1 , k − 1 S_{i,j,k}=S_{i-1,j,k}+S_{i,j-1,k}+S_{i,j,k-1}-S_{i-1,j-1,k}-S_{i-1,j,k-1}-S_{i,j-1,k-1}+S_{i-1,j-1,k-1}+A_{i-1,j-1,k-1} Si,j,k=Si1,j,k+Si,j1,k+Si,j,k1Si1,j1,kSi1,j,k1Si,j1,k1+Si1,j1,k1+Ai1,j1,k1 的性质, S S S 可以快速计算。

代码:

#include <bits/stdc++.h>

using namespace std;
typedef long long LL;
LL a[105][105][105];
LL sum[105][105][105];

int main() {
    int n;
    cin >> n;
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < n; ++j) {
            for (int k = 0; k < n; ++k) {
                cin >> a[i][j][k];
            }
        }
    }
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < n; ++j) {
            for (int k = 0; k < n; ++k) {
                sum[i + 1][j + 1][k + 1] =
                        sum[i][j + 1][k + 1] + sum[i + 1][j][k + 1] +
                        sum[i + 1][j + 1][k] - sum[i][j][k + 1] - sum[i][j + 1][k] -
                        sum[i + 1][j][k] + sum[i][j][k] + a[i][j][k];
            }
        }
    }
    int q;
    cin >> q;
    for (int i = 0; i < q; ++i) {
        int lx, rx, ly, ry, lz, rz;
        cin >> lx >> rx >> ly >> ry >> lz >> rz;
        lx--, ly--, lz--;
        LL ans = sum[rx][ry][rz] - sum[lx][ry][rz] - sum[rx][ly][rz] -
                 sum[rx][ry][lz] + sum[lx][ly][rz] + sum[lx][ry][lz] +
                 sum[rx][ly][lz] - sum[lx][ly][lz];
        cout << ans << endl;
    }
    return 0;
}

E.Manhattan Multifocal Ellipse (双指针)

题意:

给你一个二维平面上的 N N N ( x 1 , y 1 ) , ( x 2 , y 2 ) , … , ( x N , y N ) (x_1, y_1), (x_2, y_2), \dots, (x_N, y_N) (x1,y1),(x2,y2),,(xN,yN) 和一个非负整数 D D D

∑ i = 1 N ( ∣ x − x i ∣ + ∣ y − y i ∣ ) ≤ D \displaystyle \sum_{i=1}^N (|x-x_i|+|y-y_i|) \leq D i=1N(xxi+yyi)D 的整数对 ( x , y ) (x, y) (x,y) 的个数。

分析:

观察 x i , y i x_i,y_i xi,yi的范围,可知 x , y x,y x,y的取值范围是 [ − 2 × 1 0 6 , 2 × 1 0 6 ] [-2 \times 10^6,2 \times 10^6] [2×106,2×106] 。将 x , y x,y x,y分开来计算,枚举所有的 x x x,计算$ (|x-x \times i|) $的和(可以通过正反方向预处理前缀和来计算),对 y y y 同理。然后对于所有的 x , y x,y x,y,从两端开始双指针枚举和 ≤ D \le D D的情况。

代码:

#include <bits/stdc++.h>

using namespace std;
typedef long long LL;
const int N = 3e5 + 10;
LL x[N], y[N], a[N], b[N], t[1000005], ans;

int main() {
    int n, d;
    cin >> n >> d;
    for (int i = 1; i <= n; i++) {
        cin >> x[i] >> y[i];
    }
    sort(x + 1, x + n + 1);
    sort(y + 1, y + n + 1);
    x[n + 1] = LONG_LONG_MAX;
    y[n + 1] = LONG_LONG_MAX;
    for (int i = 1; i <= n; i++) {
        a[i] = a[i - 1] + x[i];
        b[i] = b[i - 1] + y[i];
    }
    for (int i = -2e6; i <= 2e6; i++) {
        LL tmp = upper_bound(x + 1, x + n + 2, i) - x;
        LL id = i * (tmp - 1) - a[tmp - 1] + a[n] - a[tmp - 1] - i * (n - tmp + 1);
        if (id <= d) {
            t[id]++;
        }
    }
    for (int i = 1; i <= d; i++) {
        t[i] += t[i - 1];
    }
    for (int i = -2e6; i <= 2e6; i++) {
        LL tmp = upper_bound(y + 1, y + n + 2, i) - y;
        LL id = i * (tmp - 1) - b[tmp - 1] + b[n] - b[tmp - 1] - i * (n - tmp + 1);
        if (id <= d) {
            ans += t[d - id];
        }
    }
    cout << ans << endl;
    return 0;
}

F.Maximum Composition (dp)

题意:

给你 N N N 个线性函数 f 1 , f 2 , … , f N f_1, f_2, \ldots, f_N f1,f2,,fN ,其中 f i ( x ) = A i x + B i f_i(x) = A_i x + B_i fi(x)=Aix+Bi .

求由 K K K 组成的序列 p = ( p 1 , p 2 , … , p K ) p = (p_1, p_2, \ldots, p_K) p=(p1,p2,,pK) f p 1 ( f p 2 ( … f p K ( 1 ) … ) ) f_{p_1}(f_{p_2}(\ldots f_{p_K}(1) \ldots )) fp1(fp2(fpK(1))) 的最大可能值。介于 1 1 1 N N N (含)之间的个不同整数的最大可能值 f p 1 ( f p 2 ( … f p K ( 1 ) … ) ) f_{p_1}(f_{p_2}(\ldots f_{p_K}(1) \ldots )) fp1(fp2(fpK(1)))

分析:

我们首先思考当用于序列 p p p K K K 整数固定不变时, p p p 具有什么样的性质?
可以发现:
f i ( f j ( x ) ) f_i(f_j(x)) fi(fj(x)) f j ( f i ( x ) ) f_j(f_i(x)) fj(fi(x)) 的排序与 x x x 无关,完全取决于 A i − 1 B i \frac{A_i-1}{B_i} BiAi1 A j − 1 B j \frac{A_j-1}{B_j} BjAj1 的排序。如果是 A i − 1 B i \frac{A_i-1}{B_i} BiAi1 > > > A j − 1 B j \frac{A_j-1}{B_j} BjAj1 ,那么就是 f i ( f j ( x ) ) > f j ( f i ( x ) ) f_i(f_j(x))>f_j(f_i(x)) fi(fj(x))>fj(fi(x))

根据这一性质,在给定 K K K 个整数用于 p p p 时,当 p p p 满足 A p 1 − 1 B p 1 ≥ A p 2 − 1 B p 2 ≥ … ≥ A p K − 1 B p K \frac{A_{p_1}-1}{B_{p_1}} \geq \frac{A_{p_2}-1}{B_{p_2}} \geq \ldots \geq \frac{A_{p_K}-1}{B_{p_K}} Bp1Ap11Bp2Ap21BpKApK1 时,值 f p 1 ( f p 2 ( … f p K ( 1 ) … ) ) f_{p_1}(f_{p_2}(\ldots f_{p_K}(1) \ldots)) fp1(fp2(fpK(1))) 取最大值。

为简单起见,假设对 ( A , B ) (A,B) (A,B) 进行排序,使 A 1 − 1 B 1 ≥ A 2 − 1 B 2 ≥ … A N − 1 B N \frac{A_1-1}{B_1} \geq \frac{A_2-1}{B_2} \geq \ldots \frac{A_N-1}{B_N} B1A11B2A21BNAN1 .

那么问题可以改写如下:

求介于 1 1 1 N N N 之间的整数序列 p p p 的最大值 f p 1 ( f p 2 ( … f p K ( 1 ) … ) ) f_{p_1}(f_{p_2}(\ldots f_{p_K}(1) \ldots)) fp1(fp2(fpK(1))) ,使得 p 1 < p 2 < … < p N p_1 < p_2 < \ldots < p_N p1<p2<<pN
我们可以用 d p dp dp来解决这问题。
当决定 p K , p K − 1 , … p K − i p_K,p_{K-1},\ldots p_{K-i} pK,pK1,pKi 时,求 f p K − i ( … f p K ( 1 ) … ) f_{p_{K-i}}(\ldots f_{p_K}(1)\ldots) fpKi(fpK(1)) 的最大值 $dp_{i,j}=( $从而求得 p K − i ≥ j ) p_{K-i} \geq j) pKij) .
我们定义 d p i , j = max ( d p i , j + 1 , A j × d p i − 1 , j + 1 + B j ) dp_{i,j}=\text{max}(dp_{i,j+1},A_j \times dp_{i-1,j+1}+B_j) dpi,j=max(dpi,j+1,Aj×dpi1,j+1+Bj) ,所求答案为 d p K , 1 dp_{K,1} dpK,1

代码:

#include <bits/stdc++.h>

using namespace std;

int main() {
    int n, k;
    cin >> n >> k;
    vector<int> a(n), b(n);
    for (int i = 0; i < n; ++i) {
        cin >> a[i] >> b[i];
    }
    vector<int> num(n);
    for (int i = 0; i < n; ++i)
        num[i] = i;
    sort(num.begin(), num.end(), [&](int i, int j) { return b[i] * (a[j] - 1) > b[j] * (a[i] - 1); });
    vector<long long> dp(k + 1, -1e9);
    dp[0] = 1;
    for (auto i: num) {
        vector<long long> tmp = dp;
        for (int j = 0; j < k; ++j)
            if (dp[j] != -1e9) {
                tmp[j + 1] = max(tmp[j + 1], dp[j] * a[i] + b[i]);
            }
        dp = move(tmp);
    }
    cout << dp[k] << endl;
    return 0;
}

赛后交流

在比赛结束后,会在交流群中给出比赛题解,同学们可以在赛后查看题解进行补题。

群号: 704572101,赛后大家可以一起交流做题思路,分享做题技巧,欢迎大家的加入。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值