首页 > 其他 > 详细

Codeforces Round #637 (Div. 2) - Thanks, Ivan Belonogov!

时间:2020-04-25 21:43:10      阅读:50      评论:0      收藏:0      [点我收藏+]

A. Nastya and Rice

所有题目链接

思路

  • 题意:给我 n个值他们的取值范围为\([a,b]\),用给了区间范围\([c,d]\),问这个n个值的总和可能在\([c,d]\)之间?

  • 分析:这个明显是判读两个区间\([n*a,n*b]、[c,d]\)是否相交的问题?我们可分类讨论连个区间是否相交,其实我们要做的判读就是 确定这两个集合一定不相交,那么剩余的情况两个集合有交点的

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<map>
#include<queue>
using namespace std;
void fre() { freopen("A.txt","r",stdin); freopen("Ans.txt","w",stdout); }
#define ll long long 

const int mxn = 2e6;


int main()
{
    /* fre(); */
    int t;
    scanf("%d", &t);
    while(t--)
    {
        int n, a, b, c, d;
        scanf("%d %d %d %d %d", &n, &a, &b, &c, &d);
        int x1 = a - b, x2 = a + b;
        x1 *= n, x2 *= n;
        int y1 = c - d, y2 = c + d;
        /* cout << x1 << " " << x2 << endl; */
        /* cout << y1 << " " << y2 << endl; */
        /* cout << x1*n << " " << x2*n << endl; */

        if(x2 < y1 || x1 > y2)
            printf("NO\n");
        else
            printf("YES\n");
    }

    return 0;
}

B. Nastya and Door

思路

  • 题意:给我一个长度为n的序列,序列中存在“极大值”概念:如果当前元素大于两边的元素,在区间的开头和结尾处不存在“极大值”,现在让我们在这个序列中选一个长度为n的连续的子序列,它包含的“极大值”的数量是多少?,最后在这个最大数量上+1,就是答案

  • 分析:用类似“前缀数组”进行预处理“极大值”的数量

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<map>
#include<queue>
using namespace std;
void fre() { freopen("A.txt","r",stdin); freopen("Ans.txt","w",stdout); }
#define ll long long 
 
const int mxn = 2e6;
 
int ar[mxn], pref[mxn];
 
 
int main()
{
    /* fre(); */
    int t;
    scanf("%d", &t);
    while(t--)
    {
        int n, k;
        scanf("%d %d", &n, &k);
        for(int i = 1; i <= n; i ++)
            scanf("%d", &ar[i]);
        for(int i = 2; i <= n - 1; i ++)
        {
            pref[i] = pref[i - 1];
            if(ar[i] > ar[i - 1] && ar[i] > ar[i + 1])
                pref[i] ++;
        }
        int mx = 0, l = 1;
        for(int i = 1; i < n - k + 2; i ++)
        {
            if(mx < pref[i + k - 2] - pref[i])
            {
                mx = pref[i + k - 2] - pref[i];
                l = i;
            }
        }
        printf("%d %d\n", mx + 1, l);
    }
 
    return 0;
}

C. Nastya and Strange Generator

思路

  • 题意:问给定的序列能不能用题中所给的算法生成。
    比如,题目中举的例子:原序列a: [ 2 3 * * 1 ],先得出 r 数组 [ 3, 3 ,3 ,4 , * ] 。r 数组的意思是:原序列当前位置右边第一个空格的位置,比如原序列 a 索引为1的位置的右边第一个空位是 3。索引为2的位置的右边第一个空位是 3。索引为4的位置的右边第一个空位是它自己 4 。索引为5的位置的右边没有空位 标记为 *
    然后得出count数组,对 r 数组中的出现的数字计数 为 [ 0 , 0 , 3 , 1 ,0 ]。3代表r 里面出现了3次。然后count数组中最大的数字出现的位置,就是原序列中选择的位置。这里count数组中索引为3的位置数字最大为3,所以原序列选择第3个位置填充数字,如果有多个最大值那么我们可以选择任意一个最大值进行填充数字。

分析:这题的题意真恶心,不过就是一个水题,我们通过??的方法构造一个长度为6的序列ar,我假设刚开始序列中已经有一个数1了「* * 1 * * 」, 代表需要我们填充数,请看下面的模拟操作

  1. 这个时候r数组为「1 2 4 4 5 6」-->count数组为:「1 1 1 2 1 1」,所以我们要第四个位置即1的后面填充数字2,所以序列ar变为了「* * 1 2 * *」
  2. 接下来r数组为「1 2 5 5 5 6」--> count 数组为「1 1 1 2 3 1」,由于3是最大的数,所以我们要在5位置即:在2的后面进行填充数字3,那么ar序列变为:「* * 1 2 3 *」,
  3. 接下来来r数组为「1 2 6 6 6 6」--> count数组为「1 1 1 1 1 1 2 3 4」,最大值为4,所以要在6位置即:在3的后面填数字4,那么ar数组为「* * 1 2 3 4」
  4. 这个时候我们应该能看出来规律:如果在我们构造的长度为n的序列中,如果如果我们一开始长度为n的count数组为「1 1 1 1 ......」,我可以在任何一个位置 填充1,一旦1的位置确定,那么剩下的数必须接着1所在的位置之后 填 \(2,3,4...\),直到填n位置之后,没位置可填写了,这个的n数组为「* * * * * 1 2 3 ...... 」那么接下来数字1的位置的前面 我们可以任意选1个位置进行接下来的填数,但是一个这个位置确定,那么我们就要 沿着这个位置之后 继续填数,,,,,如此反复就可构造出来序列了,当然理解了这个过程就会 检验所给的序列是否合格了

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<map>
#include<queue>
using namespace std;
void fre() { freopen("A.txt","r",stdin); freopen("Ans.txt","w",stdout); }
#define ll long long 

const int mxn = 2e6;

int ar[mxn], pos[mxn];


int main()
{
    /* fre(); */
    int t;
    scanf("%d", &t);
    while(t--)
    {
        int n;
        scanf("%d", &n);
        for(int i = 1; i <= n; i ++)
        {
            scanf("%d", &ar[i]);
            pos[ar[i]] = i;
        }

        int flag = 1;
        int last = n + 1;
        int tem;
        for(int i = 1; i <= n; )
        {
            tem = pos[i];
            for(int j = pos[i]; j < last; j ++)
            {
                if( ar[j] == i)
                    i ++;
                else
                {
                    flag = 0;
                    break;
                }
            }
            if(! flag)
                break;
            last = tem;
        }
        if(flag)
            printf("Yes\n");
        else
            printf("No\n");
    }

    return 0;
}

D. Nastya and Scoreboard

技术分享图片
技术分享图片

思路

  • 题意:给我我们一个n位数,每个位数上的数字由7个灯管组成,如上图,有些灯管是开着的,有些灯管是闭着的,如最上面??的那幅图表示的是\([1,9]\),问我现在可把其中灭者的一些灯管打开k个,之后这个n位数最大可以变为多大,输出出来它

  • 分析:这明显是一个动态规划问题,不过这个思路就是很难想了,首先我们先预处理每个位置到数变成1-9之间的消耗的打开灯管的次数,然后我们定义\(dp[i][j] = 1\)表示把从第i个数到最后一个数变的合理恰好要打开j个灯管,等于0则表示不行,我们从n到1逆向枚举j的值,这我样我在最需要看dp[1][k] 是否为1,就知道是否有答案了,又因为对于每一个位置i,我们可以把把那个位置上的数变成 1~9之间的任意一个数,而变成其中一个一些数,变成一个不同的数消耗的开关次数可能不同,也可能相同,对与每一个i位置要变成1~9之间的数我们从小到大枚举,这样有多个合理值的时候我们只标记最大的那个。

最后再逆项令 i从1到n找合理最大标记

代码

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<string>
#include<map>
#include<vector>
using namespace std;
void fre() { freopen("A.txt","r",stdin); freopen("Ans.txt","w",stdout); }
const int mxn = 3005;

string s[10] = { "1110111", "0010010", "1011101", "1011011", "0111010", "1101011", "1101111", "1010010", "1111111", "1111011" };

int cost[mxn][10];
int dp[mxn][mxn];

int main()
{
    ios::sync_with_stdio(false);
    /* fre(); */
    int n, k;
    cin >> n >> k;
    string st;
    for(int i = 1; i <= n; i ++)
    {
        cin >> st;
        for(int j = 0; j < 10; j ++)
        {
            for(int k = 0; k < 9; k ++)
            {
                if(st[k] == ‘1‘ && s[j][k] == ‘0‘)
                {
                    cost[i][j] = -1;
                    break;
                }
                if(st[k] == ‘0‘ && s[j][k] == ‘1‘)
                    cost[i][j] ++;
            }
        }
    }

    dp[n + 1][0] = 1;
    for(int i = n; i >= 1; i --)
    {
        for(int j = 0; j <= 9; j ++)
        {
            if(cost[i][j] == -1) continue;
            for(int l = 0; l <= k; l ++)
            {
                if(dp[i + 1][l] == 1)
                    dp[i][l + cost[i][j]] = 1;
            }
        }
    }

    string ans;
    for(int i = 1; i <= n; i ++)
    {
        for(int j = 9; j >= 0; j --)
        {
            if(cost[i][j] == -1) continue;
            if(cost[i][j] > k) continue;
            if(dp[i + 1][k - cost[i][j]] != 1) continue;
            ans += j + ‘0‘;
            k -= cost[i][j];
            break;
        }
        if(ans == "")
        {
            ans += "-1";
            break;
        }
    }
    cout << ans << endl;

    return 0;
}

Codeforces Round #637 (Div. 2) - Thanks, Ivan Belonogov!

原文:https://www.cnblogs.com/lql-nyist/p/12775400.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!