ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

[Atcoder]AtCoder Beginner Contest 234 题解

2022-01-21 17:31:40  阅读:193  来源: 互联网

标签:Atcoder cout Beginner int 题解 sum times max define


前几题直接代码。
A - Weird Function

int f(int x) {
    return x * x + 2 * x + 3;
}
cout <<  f(f(f(t)+t)+f(f(t))) << endl;

B - Longest Segment

double ans = 0;
for(int i = 1; i <= n; i++) {
    for(int j = i + 1; j <= n; j++) {
        ans = max(ans, 1.0 * (x[i] - x[j]) * (x[i] - x[j]) + (y[i] - y[j]) * (y[i] - y[j]));
    }
}
printf("%.10f\n", sqrt(ans));

C - Product
输出只由0和2组成的正整数中,第k大的数。
就是把k二进制展开就行,但是把1变成2就行。

cin >> n;
vector<int> ans;
while(n) {
    ans.push_back(n % 2 * 2);
    n /= 2;
}
if(ans.size() == 0) cout << 0 << endl;
else {
    for(int i = ans.size() - 1; i >= 0; i--) {
        cout << ans[i];
    }
    cout << endl;
}

D - Prefix K-th Max
给一个排列,对于每个大于k的位置,问前面一系列数中第k大的数是多少。
对顶堆可以nlogn,但是懒得写,直接树状数组二分也行。

#include <bits/stdc++.h>

#define Mid ((l + r) / 2)
#define lson (rt << 1)
#define rson (rt << 1 | 1)
using namespace std;
const int N = 5e5 + 1009;
int n, k, a[N];
int tree[N];
void add(int x, int y) {
    for( ; x <= n; x += x & -x)
        tree[x] += y;
}
int query(int x) {
    int ans = 0;
    for( ; x; x -= x & -x)
        ans += tree[x];
    return ans;
}
signed main() {
#ifndef ONLINE_JUDGE
    freopen("data.in", "r", stdin);
    freopen("data.out", "w", stdout);
#endif
    ios::sync_with_stdio(0);
    cin.tie(0);
    cin >> n >> k;
    for(int i = 1; i <= n; i++) cin >> a[i];
    for(int i = 1; i <  k; i++) add(n - a[i] + 1, 1);
    for(int i = k; i <= n; i++) {
        add(n - a[i] + 1, 1);
        int l = 1, r = n;
        while(l <= r) {
            if(query(Mid) >= k) r = Mid - 1;
            else l = Mid + 1;
        }
        cout << n - r << endl;
     }
    return 0;
}

E - Arithmetic Number
一个数叫做等差数当且仅当满足下面两个其中之一:

  1. 它是1位或者2位数
  2. 对于每个\(i, a_i - a_{i - 1} = a_{i + 1} - a_{i}\)
    输出大于等于x的最小的等差数。

首先,如果是只有1或2位数,直接输出就行。
不然枚举暴力枚举第一位和第二位就可以确定后面的数,时间复杂度\(T(9 * 10 * 17)\)

#include <bits/stdc++.h>
#define int long long
#define Mid ((l + r) / 2)
#define lson (rt << 1)
#define rson (rt << 1 | 1)
using namespace std;
int n, x;
char c[209];
signed main() {
#ifndef ONLINE_JUDGE
    freopen("data.in", "r", stdin);
    freopen("data.out", "w", stdout);
#endif
    ios::sync_with_stdio(0);
    cin.tie(0);
    cin >> c;
    n = strlen(c);
    for(int i = 0; i < n; i++) {
        x = x * 10 + c[i] - '0';
    }
    if(n == 1 || n == 2) {
        cout << c << endl;
    } else {
        int ans = 1ll << 61;
        for(int i = 0; i < 10; i++) {
            for(int j = -9; j <= 9; j++) {
                int t = i, now = 0;
                int f = 1;
                for(int k = 1; k <= n; k++) {
                    if(t > 9 || t < 0) {
                        f = 0;
                        break;
                    }
                    now = now * 10 + t;
                    t = t + j;
                }
                if(f && now >= x) {
                    ans = min(ans, now);
                }
            }

        }
        cout << ans << endl;
    }
    return 0;
}

F - Reordering
给定一个字符串\(S\),问有多少个不同的字符串可以由S的一个子串排列组合构成。

既然都是子串排列组合了,跟\(S\)就没啥关系了,只需要知道每个字母有多少个就行了。
然后我们统计方案只要用这个数量数组来就行了。
首先注意到组成的长度不同,方案肯定不同,可以用长度划分开方案:\(f[i][j]\)表示前\(i\)个字母组成长度为\(j\)字符串的种数。然后枚举这一个字母取多少个,然后插入新串的若干个位置,剩下的空位把原来的长度为\(j\)的串按顺序放入,就可以保证方案不同了。

#include <bits/stdc++.h>
#define int long long
#define Mid ((l + r) / 2)
#define lson (rt << 1)
#define rson (rt << 1 | 1)
using namespace std;
const int mod = 998244353;
const int N = 2e5 + 1009;
int n, cnt[29], f[29][5009];
char c[5009];
int inv[N], fac[N];
void init() {
    inv[0] = inv[1] = fac[0] = fac[1] = 1;
    for(int i = 2; i < N; i++) inv[i] = (mod - mod / i) * inv[mod % i] % mod;
    for(int i = 2; i < N; i++) inv[i] = inv[i] * inv[i - 1] % mod;
    for(int i = 2; i < N; i++) fac[i] = fac[i - 1] * i % mod;
}
int C(int n, int m) {
    return fac[n] * inv[n - m] % mod * inv[m] % mod;
}
signed main() {
#ifndef ONLINE_JUDGE
    freopen("data.in", "r", stdin);
    freopen("data.out", "w", stdout);
#endif
    ios::sync_with_stdio(0);
    cin.tie(0);
    init();
    cin >> c; n = strlen(c);
    for(int i = 0; i < n; i++) {
        cnt[c[i] - 'a' + 1]++;
    }
    int sum = 0;
    f[0][0] = 1;
    for(int i = 1; i <= 26; i++) {
        for(int j = 0; j <= sum; j++) {
            for(int k = 0; k <= cnt[i]; k++) {
                f[i][j + k] = (f[i][j + k] + f[i - 1][j] * C(j + k, k) % mod) % mod;
            }
        }
        sum += cnt[i];
    }
    int ans = 0;
    for(int i = 1; i <= n; i++) {
        ans = (ans + f[26][i]) % mod;
    }
    cout << ans << endl;
    return 0;
}

G - Divide a Sequence
给定一个数组,对于一种划分成\(k\)段的方案\(P\),\(f(P)\)为每一段的最大值减最小值的乘积:\(\prod_{i = 1}^{k} max(B_i) - min(B_i)\),\(B_i\)为第\(i\)段这个集合。
问对于所有的划分方案,\(\sum f(P)\)。

\(n^2\)的做法挺好想的,f[i]表示前i个数任意划分的乘积的和,只需要枚举最后一段的长度就行了。

\[f(i) = \sum (f(j - 1) \times (max_{k = j}^{i} a_k - min_{k = j}^{i} a_k)) \]

代码:

  f[0] = 1;
  for(int i = 1; i <= n; i++) {
      int maxn = a[i];
      int minn = a[i];
      for(int j = i; j >= 1; j--) {
          maxn = max(maxn, a[j]);
          minn = min(minn, a[j]);
          f[i] = (f[i] + f[j - 1] * (maxn - minn) % mod) % mod;
      }
  }
  cout << f[n] << endl;

显然,跑的太慢了,考虑优化,重点就在第二个循环。
我们给每个位置一个后缀max和min的值,每次加入i位置的值,有若干个位置的max和min会更新。
显然,max是递减的,min是递增的。
由于这两个问题等价,我们下面只考虑max的处理。
对于每次加入一个新的数字,只有末尾的若干个max值会被变成\(a(i)\),同时对\(f(i)\)的影响就是\(\delta max_j * f(j)\)。
当一段数字都变成\(a(i)\)之后,其实在之后如果要改变就会一起改变相同的\(\delta max\)了,所以可以直接把所有的\(f\)值放在一起。
这个过程就是单调栈的处理方式,我们用单调栈维护每个位置的\(sumf\)和\(max\),就可以了。

这里只计算了变大的值,不变的部分直接\(f(i) += f(i - 1)\)就行。

#include <bits/stdc++.h>
#define int long long
#define Mid ((l + r) / 2)
#define lson (rt << 1)
#define rson (rt << 1 | 1)
using namespace std;
const int mod = 998244353;
const int N = 3e5 + 1009;
int n, a[N], f[N], submax[N], submin[N];
struct node {
    int f, v;
};
stack<node> maxst, minst;
signed main() {
#ifndef ONLINE_JUDGE
    freopen("data.in", "r", stdin);
    freopen("data.out", "w", stdout);
#endif
    ios::sync_with_stdio(0);
    cin.tie(0);
    cin >> n;
    for(int i = 1; i <= n; i++) cin >> a[i];
    maxst.push({1, a[1]});
    minst.push({1, a[1]});
    for(int i = 2; i <= n; i++) {
        int maxs = 0, mins = 0;
        f[i] = f[i - 1];
        while(!maxst.empty() && maxst.top().v < a[i]) {
            f[i] = (f[i] + maxst.top().f * (a[i] - maxst.top().v) % mod) % mod;
            maxs = (maxs + maxst.top().f) % mod;
            maxst.pop();
        }
        while(!minst.empty() && minst.top().v > a[i]) {
            f[i] = (f[i] + minst.top().f * (minst.top().v - a[i]) % mod) % mod;
            mins = (mins + minst.top().f) % mod;
            minst.pop();
        }
        maxst.push({(maxs + f[i - 1]) % mod, a[i]});
        minst.push({(mins + f[i - 1]) % mod, a[i]});
    }
    cout << f[n] << endl;
    return 0;
}

Ex - Enumerate Pairs
很奇妙的题,看题解做出来的,这里根据自己的理解简要翻译一下官方题解。
我们把\((x, y)\)放到\((x/k, y/k)\)(整除)这个集合中,对于每个点,跟他距离小于等于k的点只会出现在

\[(x/k+i,y/k+j), i\in[-1, 1], j\in[-1, 1] \]

中。
这是显然的,假如\(x,y\)的差距超过k,那么欧几里得距离一定大于k。
之后只要爆搜这些集合就可以找到所有的点对了,复杂度是\(O(N + M)\)。

方法很简单,但是复杂度不显然,下面是复杂度证明。
\(B_{X,Y}\)是集合\((X,Y)\)的点数,\(f(x)\)是包含x个点的集合的点的合法点对数量。
显然\(f(x)\le x^2\),现在要证明\(f(x)\)的下界为\(x^2\),目的是为了说明\(B_{X,Y}^2\)和\(f(B_{X,Y})\)同阶。

一个边长为\(\frac{K}{\sqrt(2)}\)的矩形中的任意两点距离小于\(K\)(最远的点对距离都为\(K\))。
而一个边长为\(K\)的矩形可以由4个这样的矩形覆盖,假如矩形中有x个点,那么根据鸽巢原理,一定有\(\frac{x}{4}\)个点在其中一个小矩形中,那么小矩形中的点对数大于\(\frac{\frac{x}{4} * (\frac{x}{4} - 1)}{2}\)。这个数量级为\(O(n^2)\),所以\(B_{X,Y}^2\)和\(f(B_{X,Y})\)同阶。

由于\(\sum f(B_{X,Y})\le M\),得到\(O(\sum B_{X,Y}^2) = O(M)\)

证明这个复杂度有什么用呢?

我们的算法计算的都是

\[\sum_{X, Y} \sum_{i = -1}^{1} \sum_{j = -1}^{1} B_{X,Y} \times B_{X + i, Y + j} \]

根据均值不等式:

\[B_{X,Y} \times B_{X + i, Y + j} \le \frac{1}{2} \times (B_{X,Y} ^ 2 + B_{X + i, Y + j}^2) \]

所以

\[\sum_{X, Y} \sum_{i = -1}^{1} \sum_{j = -1}^{1} B_{X,Y} \times B_{X + i, Y + j} \le \sum_{X, Y} \sum_{i = -1}^{1} \sum_{j = -1}^{1} \frac{1}{2} \times (B_{X,Y} ^ 2 + B_{X + i, Y + j}^2) \]

\[\le \sum_{X, Y} \frac{9}{2} \times (B_{X,Y} ^ 2) \]

所以:

\[O(\sum_{X, Y} \sum_{i = -1}^{1} \sum_{j = -1}^{1} B_{X,Y} \times B_{X + i, Y + j}) = O(N + M) \]

下面是代码:

#include <bits/stdc++.h>
#define int long long
#define Mid ((l + r) / 2)
#define lson (rt << 1)
#define rson (rt << 1 | 1)
using namespace std;
const int N = 2e5 + 1009;
const int lim = 2e9;
const int dx[] = {-1, -1, -1, 0, 0, 0, 1, 1, 1};
const int dy[] = {-1, 0, 1, -1, 0, 1, -1, 0, 1};
int n, k;
struct node {
    int x, y;
} p[N];
int dis(int a, int b) {
    return (p[a].x - p[b].x) * (p[a].x - p[b].x) + (p[a].y - p[b].y) * (p[a].y - p[b].y);
}
map<int, vector<int> > g;
int get(int x, int y) {
    return x * lim + y;
}
vector<node> ans;
signed main() {
#ifndef ONLINE_JUDGE
    freopen("data.in", "r", stdin);
    freopen("data.out", "w", stdout);
#endif
    ios::sync_with_stdio(0);
    cin.tie(0);
    cin >> n >> k;
    for(int i = 1; i <= n; i++) {
        int x, y;
        cin >> x >> y;
        p[i] = {x, y};
        g[get(x / k, y / k)].push_back(i);
    }
    for(int i = 1; i <= n; i++) {
        int x = p[i].x / k;
        int y = p[i].y / k;
        for(int j = 0; j < 9; j++) {
            int xx = x + dx[j];
            int yy = y + dy[j];
            for(auto t : g[get(xx, yy)]) {
                if(i >= t) continue;
                if(dis(i, t) <= k * k) {
                    ans.push_back({i, t});
                }

            }
        }
    }
    sort(ans.begin(), ans.end(), [](const node &a, const node &b) {
        if(a.x == b.x) return a.y < b.y;
        else return a.x < b.x;
    });
    cout << ans.size() << endl;
    for(auto x : ans) {
        cout << x.x << " " << x.y << endl;
    }
    return 0;
}

标签:Atcoder,cout,Beginner,int,题解,sum,times,max,define
来源: https://www.cnblogs.com/onglublog/p/15830756.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有