ICode9

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

AtCoder Beginner Contest 234

2022-01-10 13:34:55  阅读:189  来源: 互联网

标签:AtCoder temp Beginner int ++ num vec ans 234


A - Weird Function

给出f函数表达式,求:f(f(f(t)+t)+f(f(t)))
签到题
重复利用的代码,最好写一个函数出来

#include <bits/stdc++.h>
using namespace std;

int f(int x)
{
    return x * x + 2 * x + 3;
}
int main() {
    int t;
    cin >> t;
    int ans = 0;

    int ft = f(t);
    int ftt = ft + t;
    int fftt = f(ftt);
    int fft = f(ft);
    ans = f(fftt +  fft);
    cout << ans << endl;
    return 0;
}

B - Longest Segment

给出n个点,找出两点间最长距离
签到题

#include <bits/stdc++.h>
using namespace std;

double f(double x1, double y1, double x2, double y2)
{
    return (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2);
}

int main() {
    int n;
    cin >> n;
    vector<pair<double, double>> vec(n);
    double ans = 0;
    for(int i = 0; i < n; i ++)
    {
        double x1, y1;
        cin >> x1 >> y1;
        vec[i] = {x1, y1};
    }
    for(int i = 0; i < n; i ++)
    {
        for(int j = i + 1; j < n; j ++)
        {
            double temp = f(vec[i].first, vec[i].second, vec[j].first, vec[j].second);
            if(temp - ans > 1e-18) ans = temp;
        }
    }
    printf("%.10f\n", sqrt(ans));
    return 0;
}

C - Happy New Year!

求第k个仅由0和2组成的十进制数字。
二进制模拟
此题中:十进制数字中,填写2的可以看成二进制中的1, 填写0的可以看成二进制中的0。 这样每一个仅由0、2组成的十进制数字均唯一对应一个二进制数字。在此规则下,把该十进制转化为相应的二进制表示,逆序输出即可。(大小关系不变)

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int main() {
    LL n;
    cin >> n;
    vector<int> vec;
    while(n)
    {
        if(n & 1) vec.push_back(2);
        else vec.push_back(0);
        n >>= 1;
    }
    for(int i = vec.size() - 1; i >= 0; i --)
    {
        printf("%d", vec[i]);
    }
    return 0;
}

D - Prefix K-th Max

题目大意:给出一个排列P, 从前i个数中,找到第k大的数(i >= k时)。
STL应用 此处给出两种写法 堆、set
堆(优先队列版本)

思路:
小根堆,保证堆顶为堆中最小的元素。我们维护堆中的元素为k个,堆顶的即为所求。即堆中一定有 k - 1个大于堆顶的元素,堆顶即为第k大的元素

//从前i个数中,找到第k大的数(i >= k时)

#include <bits/stdc++.h>
using namespace std;
int main(){
    int n, k;
    scanf("%d%d", &n, &k);
    priority_queue<int, vector<int>, greater<int>> que; //小根堆
    for(int i = 1; i <= n; i ++)
    {
        int num;
        scanf("%d", &num);
        que.push(num);
        if(i == k)
        {
            printf("%d\n", que.top());
        }
        else if(i > k)
        {
            que.pop();
            printf("%d\n", que.top());
        }
    }
}

set版本
set的特性:去重、自动排序(默认从小到大)

  1. 当i <= k时,我们直接插入num, i == k时,直接输出set头元素。
  2. 当i > k时, set中第一个元素last(为前i个的第k大),如果num > last, 则将last删除,并将num插入set中。set中的第一个元素仍为第k大。
//从前i个数中,找到第k大的数(i >= k时)

#include <bits/stdc++.h>
using namespace std;
int main(){
    int n, k;
    scanf("%d%d", &n, &k);
    set<int> st;
    for(int i = 1; i <= n; i ++)
    {
        int num;
        scanf("%d", &num);
        if(i <= k) st.insert(num);
        if(i == k)
        {
            printf("%d\n", *st.begin());
        }
        else if(i > k)
        {
            auto last = *st.begin();
            if(num > last){
                st.insert(num);
                st.erase(last);
            }
            printf("%d\n", *st.begin());
        }
    }
}

E - Arithmetic Number

题目大意:当一个十进制数字满足:d[2] - d[1] = d[3] - d[2] = …= d[n] - d[n - 1]时(一共由n位数字组成,从低位到高位以此为d[1] …到d[n]),就是一个arithmetic number。
给出x, 求不小于x的最小的arithmetic number。
思维、代码实现
思路:

  1. 十进制数字由0-9组成,且x < 10 ^ 17, 不多于18位。直接枚举d[n] - d[n - 1]的值,最高位的数字,最多18位,即可。

#include <bits/stdc++.h>
using namespace std;
typedef long long  LL;
int main(){
    LL n;
    cin >> n;
    LL ans = 1e18;
    for(int i = 0; i < 10; i ++)
    {
        for(int j = 0; j < 10; j ++)
        {
            int d = j - i, temp = i; //两者之间的差值,前一个数
            LL y = 0;
            for(int k = 0; k < 18; k ++)
            {
                if(temp < 0 || temp > 9){
                    break;
                }
                y = y * 10 + temp;
                temp += d;
                if(y >= n) ans = min(ans, y);
            }
        }
    }
    cout << ans <<endl;
}

F - Reordering

题目大意:
S是由小写字母组成的长度为[1, 5000]的字符串,求能从S中得到多少非空子串(此题中字母出现的顺序可以和S不一样)。
组合数、dp

分析:

  1. 没有思路时,观察样例,一个字串可以包含两部分:组成的子串包含的字母;以及各个字母所用的数量。由此我们可以想到dp
  2. 状态表示:dp[i,j]:从前i个字母中选(1 <= i <= 26),组成长度为j的方案数
  3. 状态计算:
    (freqi:表示 i + ‘a’ 这个字母出现了多少次。)
    在这里插入图片描述
    即:从前i - 1个字母中选,选择长度为(j - k)的方案数(即dp[i-1][j-k]) * 从j个位置中选择k个该字母的位置方法数(即g数组). 再求和(0 <= k <= min(j, freqi))

在这里插入图片描述

思考:从i个位置中选择j个位置该怎么求?
(1)第i个位置选, 则从前i-1中选j个。即g[i-1][j-1]
(2)第i个位置不选:即g[i-1][j]
所以 g[i][j] = g[i-1][j-1]+g[i-1][j]

代码如下:

  1. 解释sum数组:从前i个字母中选,总长度最大为多少。
  2. 解释第三重循环:当我枚举选择第三个字母的数量时,会超时;而枚举前i-1个选择的数量时,不会超时。(会卡aaaaaaaaaa这样的数据)
#include <bits/stdc++.h>
using namespace std;
const int N = 5010, mod = 998244353;
typedef long long LL;
int g[N][N];
char str[N];
int cnt[30];
int sum[30]; //前i个字母一共有多少个
int dp[30][N];
int main(void)
{
    cin >> str;
    int n = strlen(str);
    //预处理g数组
    for(int i = 0; i <= n; i ++)
    {
        g[i][0] = 1;
        for(int j = 1; j <= i; j ++)
        {
            g[i][j] = (g[i - 1][j] + g[i - 1][j - 1]) % mod;
        }
    }
    //处理cnt数组,每个字母有多少个
    for(int i = 0; i < n; i ++)
    {
        cnt[str[i] - 'a' + 1] ++;
    }
    for(int i = 1; i <= 26; i ++) sum[i] = sum[i-1] + cnt[i];

    dp[0][0] = 1;
    for(int i = 1; i <= 26; i ++)
    {
        for(int j = 0; j <= sum[i]; j ++) //总长度
        {
          /*
            for(int k = 0; k <= min(cnt[i], sum[i]); k ++) //选择第i个字母的个数
            {
                dp[i][j] = (dp[i][j] + (LL) dp[i - 1][j - k] * g[j][k]) % mod;
            }
          */
          for(int k = 0; k <= min(j, sum[i - 1]); k ++) //前i-1个字母组成的长度
          {
              if(j - k <= cnt[i]) dp[i][j]  = (dp[i][j] + (LL)dp[i - 1][k] * g[j][j - k]) % mod;
          }
        }
    }
    LL ans = 0;
    for(int i = 1; i <= sum[26]; i ++)
    {
        ans = (ans + dp[26][i]) % mod;
    }
    cout << ans <<endl;
    return 0;
}

标签:AtCoder,temp,Beginner,int,++,num,vec,ans,234
来源: https://blog.csdn.net/m0_51508220/article/details/122406525

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

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

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

ICode9版权所有