Codeforces Round 987 (Div. 2) ABCD

链接:

Codeforces Round 987 (Div. 2)

A:Penchick and Modern Monument

大意:

       单调非增序列操作多少步变成单调非减

思路:

       最后的数一定是相同的,为出现次数最多的那个数,结果就是n减去出现次数最多的数

代码:

#include <bits/stdc++.h>

using namespace std;
#define int long long
const int N = 2e5 + 10, INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
#define pb push_back
#define  vi vector<int>
#define  vvi vector<vector<int>>
#define  vii vector<pair<int, int>>
#define ff first 
#define ss second 
// ++   ~!    */+-    <<>>    <>  ==   &^|   &&|| =


void solve()
{
    int n;cin >> n;
    vi a(n + 1);
    for (int i = 1; i <= n; i++)cin >> a[i];
    int mx = 0;
    for (int i = 1; i <= n; i++)
    {
        int j = i;
        while (i <= n && a[i] == a[j])i++;
        mx = max(i - j, mx);
        i--;
    }
    cout << n - mx << endl;
}

signed main()
{
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);

    int t = 1;
    cin >> t;
    while (t--) solve();

    return 0;
}
/*   /\_/\
*   (= ._.)
*   / >  \>
*/

 B:Penchick and Satay Sticks

大意:

        一个排列转换成123456...n的最小字典序排列,每次转换只能相邻1个并且数值不能相差超过1,求是否能转换 

思路:

        相差不能超过1,则只能与位置相邻的数进行交换,即如果i不在位置i上,必然就在位置i-1或者i + 1上,如果都没有,就不能转换

        那么可以从左到右遍历,如果 i !=a[i] 并且跟后边差1,就跟右边交换即可,换完还不等,就不能转换

代码:

#include <bits/stdc++.h>

using namespace std;
#define int long long
const int N = 2e5 + 10, INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
#define pb push_back
#define  vi vector<int>
#define  vvi vector<vector<int>>
#define  vii vector<pair<int, int>>
#define ff first 
#define ss second 
// ++   ~!    */+-    <<>>    <>  ==   &^|   &&|| =
   

void solve()
{
    int n;cin >> n;
    vi a(n + 1);
    for (int i = 1; i <= n; i++)cin >> a[i];


    for (int i = 1; i <= n; i++)
    {
        if (a[i] != i)
        {
            if(i + 1 <= n && a[i + 1] == i && abs(a[i + 1] - a[i])==1)
                swap(a[i], a[i + 1]);
            else
            {
                cout << "NO" << endl;
                return;
            }
        }
    }
    cout << "YES" << endl;
}
 
signed main()
{
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);

    int t = 1; 
    cin >> t;
    while (t--) solve();
       
    return 0;
}
/*   /\_/\
*   (= ._.)
*   / >  \>
*/

C:Penchick and BBQ Buns

大意:

        给一个长度n的每个点上都赋一个值,如果赋了相同的值,任意两个相同的值之间要满足距离之差等于某个整数的平方和,求赋值方案,没有则输出-1

思路:

        先对n进行奇偶分析,如果偶数的话就好了,直接两两相邻,距离差为1

        奇数的话可以转换成偶数的情况,我们需要一个三个点的那就是距离为9和距离为16的,最小的情况下给1,10,26同种,发现1-10之间可以填偶数个,直接填就行,10到26之间填奇数个,可以多一个距离差为4的一个在10-26之内,一个在之外,这样距离差为4的里面再塞一对,前面的几对也塞一下就行了,所以27是最小的奇数合法情况

代码:

#include <bits/stdc++.h>

using namespace std;
#define int long long
const int N = 2e5 + 10, INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
#define pb push_back
#define  vi vector<int>
#define  vvi vector<vector<int>>
#define  vii vector<pair<int, int>>
#define ff first 
#define ss second 
// ++   ~!    */+-    <<>>    <>  ==   &^|   &&|| =


void solve()
{
    int n;cin >> n;
    if (n & 1)
    {
        if (n < 27)
            cout << -1 << endl;
        else
        {
            vi ans(n + 1);
            int cnt = 2;int num = 0;
            for (int i = 1; i <= n; i++)
            {
                if (i == 1 || i == 10 || i == 26)ans[i] = 1e6;
                else if (i == 23 || i == 27)ans[i] = 1e6-1;
                else
                {
                    ans[i] = cnt;num++;
                    if (num == 2)
                    {
                        num = 0;
                        cnt++;
                    }
                }

            }
            for (int i = 1; i <= n; i++)cout << ans[i] << ' ';

        }
    }
    else
    {
        int num = n / 2;
        for (int i = 1; i <= num; i++)
            cout << i << " " << i << " ";
        cout << endl;
    }


}

signed main()
{
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);

    int t = 1;
    cin >> t;
    while (t--) solve();

    return 0;
}
/*   /\_/\
*   (= ._.)
*   / >  \>
*/

D:Penchick and Desert Rabbit

大意:

        一个数组,位于i的数可以跳到右边比他小的数,可以跳到左边比他大的数,求从每一位开始最后可以跳到的最大数

思路:

        有一个性质就是,一个数如果能跳到另一个数上,那么这两个位置的答案会一样

        首先要想的是要跳到最大,应该是先往右跳,跳到最靠右的,然后往左跳才会有最大的,但是从左到右找最靠右的不太好找,pass

        从右往左找的话,可以知道最靠右的就是自己,然后这个的答案就是前n个取最大,并且可知右边的能跳的肯定大于等于左边的能跳到的数,对于位置i,直接取i后面数的最小值,看看i是否大于后面最小值,如果大于,那么,那么i肯定直接或间接能到i + 1,那么i的答案跟i + 1的答案是相同的;如果小于等于,那么i到不了右边任何一个,只能取前面的最大值。

        所以求一下前缀最大值和后缀最小值依次从右往左即可。

代码:

#include <bits/stdc++.h>

using namespace std;
#define int long long
const int N = 2e5 + 10, INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
#define pb push_back
#define  vi vector<int>
#define  vvi vector<vector<int>>
#define  vii vector<pair<int, int>>
#define ff first 
#define ss second 
// ++   ~!    */+-    <<>>    <>  ==   &^|   &&|| =


void solve()
{
    int n;cin >> n;
    vi a(n + 1);
    for (int i = 1; i <= n; i++)cin >> a[i];
    vi ans(n + 1), p(n + 1), s(n + 1);
    p[1] = a[1], s[n] = a[n];
    for (int i = 2; i <= n; i++)
        p[i] = max(p[i - 1], a[i]);
    for (int i = n - 1; i > 0; i--)
        s[i] = min(a[i], s[i + 1]);
    
    ans[n] = p[n];
    for (int i = n - 1; i; i--)
    {
        if (p[i] > s[i + 1])ans[i] = ans[i + 1];
        else ans[i] = p[i];
    }
    for (int i = 1; i <= n; i++)cout << ans[i] << ' ';
    cout << endl;
}

signed main()
{
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);

    int t = 1;
    cin >> t;
    while (t--) solve();

    return 0;
}
/*   /\_/\
*   (= ._.)
*   / >  \>
*/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值