Codeforces Round #740 (Div. 2)

A Simply Strange Sort

题目大意

给定一个长度为n的数组,对根据操作次数数组进行两种操作

  • 操作次数为奇数则,枚举i为1, 3, 5…n - 2,如果a[i] > a[i + 1]交换i和i+1
  • 操作次数为奇数则,枚举i为2, 3, 6…n - 1,如果a[i] > a[i + 1]交换i和i+1
主要思路

根据题意模拟即可,最坏情况数组为n, n - 1, … 1,复杂度为n^2

AC代码
#include <bits/stdc++.h>

#define int long long
using namespace std;
#define debug(a) cout << #a << " = " << a << endl;
#define x first
#define y second
typedef long long ll;
const int N = 200010, mod = 998244353;
int n, m;
int a[N], b[N];
int st[N];

signed main(void)
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    
    int T;
    cin >> T;
    while(T--)
    {
        cin >> n;
        for(int i = 1; i <= n; i++) cin >> a[i];
        int res = 0;
        while(!is_sorted(a + 1, a + n + 1))
        {
            res++;
            if(res % 2)
            {
                for(int i = 1; i <= n - 2; i += 2)
                {
                    if(a[i] > a[i + 1]) swap(a[i], a[i + 1]);
                }
            }
            else
            {
                for(int i = 2; i <= n - 1; i += 2)
                {
                    if(a[i] > a[i + 1]) swap(a[i], a[i + 1]);
                }
            }
        }
        cout << res << endl;
    }
    return 0;
}

B Charmed by the Game

题目大意

A和B轮流发球,未规定谁先发球,A发球若B接到则B得分,否则A得分,接发球的人接到一球为则记为1次接到发球,给定两人的最终比分,问两人接到发球的总次数的可能是哪些

主要思路

两人发球的最少次数是(a + b) / 2,所以两人接到发球的次数最小值为t = (a + b) / 2 - min(a, b),如果比这个值更小那么一定不会以a和b的比分结束比赛,因为两人轮流发球,一人发一次。

接下来考虑最大值,与最小值相同将接到发球和未接到发球反转即可,最大值为a + b - t,a+b为总发球次数

  • 当a+b为偶数时,假设当前比分情况已经确定,我们修改一个人的未接到发球改为接到发球,那么另一个人也许这样修改,那么对答案的修改值就是2
  • 当a+b为偶数时,假设当前比分情况已经确定,我们修改一个人的未接到发球改为接到发球,那么我们只要修改第一个发球人的顺序即可对答案修改值为1
AC代码
#include <bits/stdc++.h>

#define int long long
using namespace std;
#define debug(a) cout << #a << " = " << a << endl;
#define x first
#define y second
typedef long long ll;
const int N = 200010, mod = 998244353;
int n, m;

signed main(void)
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    
    int T;
    cin >> T;
    while(T--)
    {
        int a, b;
        cin >> a >> b;
        int sum = (a + b) / 2;
        int t = sum - min(a, b);
        
        vector<int> res;
        if((a + b) % 2)
        {
            for(int i = t; i <= a + b - t; i++)
            {
                res.push_back(i);
            }
        }
        else
        {
            for(int i = t; i <= a + b - t; i += 2)
            {
                res.push_back(i);
            }
        }
        cout << res.size() << endl;
        for(auto i : res)
        {
            cout << i << ' ';
        }
        cout << endl;
    }
    return 0;
}

C Deep Down Below

题目大意

给定n组怪兽,英雄的值必须大于怪兽才能将其击杀,并且英雄的值+1,必须击杀每一组的所有怪兽才能击杀下一组,问英雄的最小值

主要思路

我们预处理出每一组需要的最小值以及击杀一组后的最小值,对所有区间排序,然后遍历所有组求英雄的最小值(具体看代码)

AC代码
#include <bits/stdc++.h>

#define int long long
using namespace std;
#define x first
#define y second
typedef long long ll;
const int N = 200010, mod = 1e9+7;
int n, a[N];
pair<int, int> p[N];

signed main(void)
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    
    int T;
    cin >> T;
    while(T--)
    {
        cin >> n;
        for(int i = 0; i < n; i++)
        {
            int t;
            cin >> t;
            int maxa = 0;
            for(int j = 0; j < t; j++)
            {
                cin >> a[j];
                maxa = max(maxa, a[j] - j + 1);
            }
            p[i] = {maxa, maxa + t};
            //cout << p[i].x << ' ' << p[i].y << endl;
        }
        
        sort(p, p + n);
        
        int ans = p[0].x;
        int l = p[0].x, r = p[0].y;
        for(int i = 1; i < n; i++)
        {
            if(p[i].x <= r)
            {
                r += p[i].y - p[i].x;//如果能满足这一组,那么有区间加上下一组的增加的值
            }
            else
            {
                l += p[i].x - r;//如果不能满足这一组,那么左区间就要加上中间的差值来满足能击杀这一组
                r = p[i].y;
            }
        }
        cout << l << endl;
    }
    return 0;
}

D1 Up the Strip (simplified version)

题目大意

当前在n点,每次你能跳跃到1~n - 1或者到n/i (2 <= i <= x),问到1号点有多少种方案

主要思路

dp+整除分块

dp[i]表示1到 i 的方案数

  • 首先1~x的任意一个区间都能到x,那么dp[i]首先要加上 ∑ j = 1 i − 1 d p [ j ] \sum_{j=1}^{i-1}{dp[j]} j=1i1dp[j],可以通过前缀和维护
  • 其次考虑整除,我们发现 n i \frac{n}{i} in的值在一定区间都是相同的,每一个值相同的块的最后一个数为n/(n / i),具体整除分块可见:整除分块,于是用整除分块处理每一个数即可, 整除分块复杂度为根号n

于是dp[i] = ∑ j = 1 i − 1 d p [ j ] + ∑ d p [ i l ] \sum_{j=1}^{i-1}{dp[j]} + \sum_{}^{}{dp[\frac{i}{l}]} j=1i1dp[j]+dp[li]

AC代码
#include <bits/stdc++.h>

#define int long long
using namespace std;
#define debug(a) cout << #a << " = " << a << endl;
#define x first
#define y second
typedef long long ll;
const int N = 200010;
int n, m;
int dp[N], sum[N];//sum维护前缀和

signed main(void)
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    
    int T;
    T = 1;
    while(T--)
    {
        cin >> n >> m;
        dp[1] = sum[1] = 1;
        for(int i = 2; i <= n; i++)
        {
            dp[i] = sum[i - 1];
            for(int l = 2, r; l <= i; l = r + 1)
            {
                r = i / (i / l);
                dp[i] = (dp[i] + (r - l + 1) * dp[i / l]) % m;
            }
            sum[i] = (sum[i - 1] + dp[i]) % m;
        }
        cout << dp[n] << endl;//答案为1走到n位置的方案数
    }
    return 0;
}

D2由于我实在太菜还没过,争取明天补上

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值