Codeforces Round #637 (Div. 2) A~D

Codeforces Round #637 (Div. 2) A~D

http://codeforces.com/contest/1341/

A. Nastya and Rice

题意

\(n\) 个范围在 \([a-b,a+b]\) 的数字,询问他们的和能否在区间 \([c-d,c+d]\) 内。

解题

\(n\) 个数字和的范围是 \([n(a-b),n(a+b)]\) ,判断是否与 \([c-d,c+d]\) 存在交集即可。

def scanf():
    return list(map(int,input().split()))

for t in range(int(input())):
    n,a,b,c,d = scanf()
    p = n*(a-b); q = n*(a+b)
    if(p>c+d or q<c-d):	print("NO")
    else:	print("YES")

B. Nastya and Door

题意

给定一个正整数序列,代表连绵的山脉。序列中如果存在 \(a_{i-1}<a_i \land a_i>a_{i+1}\) 的位置,则称 \(a_i\) 为山峰。

有一个巨大的门,把这个门水平扔山上问最多能分成几份。这个门或门的碎片,遇到山峰之后就会分成两半。

解题

这个题是真的难翻译,又长又玄幻,不过题目还算简单。

差分,记录位置前面的山峰数量,寻找山峰最多的区间,在这里把门扔下去分成的份数最多,为山峰数\(+1\)

注意下边界的判定,题目中说区间边界的山峰不会分割门。

#include<bits/stdc++.h>
#define ll long long

#define fr(i,n) for(int i=0;i<n;i++)
#define frs(i,n,flag)   for(int i=0;i<n&&flag;i++)

#define frr(i,j,n) for(int i=j;i<n;i++)
#define r_frr(i,j,n) for(int i=n-1;i>=j;i--)

#define frrs(i,j,n,flag)    for(int i=j;i<n&&flag;i++)
#define r_frrs(i,j,n,flag)    for(int i=n-1;i>=j&&flag;i--)

#define arend(i,n) ((i!=n-1)?" ":"\n")
#define memset0(dp) memset(dp,0,sizeof(dp))
#define print_arr(begin,end)    for(auto it = begin;it!=end;it++)  cout<<*it<<arend(it,end);
#define log_this(name,value)    cout<<name<<": "<<value<<endl;
#define e4 10004
#define e5 100005
#define e6 1000006
#define e7 10000007
#define e9 1000000000
#define INF 9999999
using namespace std;
int     to_int(string s)    {stringstream ss;ss<<s;int a;ss>>a;return a;}
string  to_str(double a)    {stringstream ss;ss<<a;return ss.str();}

int a[2*e5];
int ct[2*e5];	//记录区间 (0,i) 的山峰数量,注意是开区间

int main(){

    cin.tie(0);
    //ios::sync_with_stdio(false);
    //cout<<setiosflags(ios::fixed)<<setprecision(0);

    //freopen("1.out","w",stdout);

    int t;
    while(cin>>t){
        while(t--){
            int n,k;cin>>n>>k;
            fr(i,n) cin>>a[i];
            ct[0] = 0;
            ct[1] = 0;
            frr(i,1,n-1){
                ct[i+1] = ct[i];
                if(a[i]>a[i-1]&&a[i]>a[i+1]){
                    ct[i+1]++;
                }
            }
            ct[n] = ct[n-1];
            int ans = -1;
            int l = 0;
            frr(i,0,n-k+1){
                if(ans<ct[i+k-1]-ct[i+1]){
                    l = i;
                    ans = ct[i+k-1] - ct[i+1];
                }
            }
            cout<<ans+1<<" "<<l+1<<endl;
        }
    }
    return 0;
}

C. Nastya and Strange Generator

题意

有一个随机的数字生成器,按照如下生成规则。

  • \(i\) 次操作将数字 \(i\) 按照下面规则填入;

  • \(r_j\) 表示位置 \(j\) 之后的第一个为空的位置;

  • \(count_t\) 表示位置 \(t\) 被其他位置选做 \(r_j\) 的次数,即 \(r.count(t)\)

  • 每次只能选取 \(count_t\) 最大的位置填入 \(i\)

  • 如果有多个相同的最大值,则可以从中选取任意一个。

给定一个由 \(n\) 个不同数字组成的数组,询问能否使用该生成器生成。

解题

这个题也是题面不是很友好,读题面和理解题意用了很长时间。在50分钟的时候过题没想到还能排到1900,说明很多人都被这题面卡住了(绝了

通过举例模拟填充过程发现,填充机制很简单。一旦选取位置 \(t\) 填充数字 \(i\) ,那么位置 \(t+1\) 一定是序列中 \(count\) 值最大的,所以我们的 \(i+1\) 必须填充到位置 \(t+1\) 上,以此类推,直至位置被已被填充或者到达末尾。最后得到的填充序列一定满足以下两个条件:

  • 由每小段连续递增子序列组成;
  • 前面的连续递增子序列的元素一定大于后面连续子序列的元素。

判断输入序列是否同时满足上面两个条件即可。

#include<bits/stdc++.h>
#define ll long long
 
#define fr(i,n) for(int i=0;i<n;i++)
#define frs(i,n,flag)   for(int i=0;i<n&&flag;i++)
 
#define frr(i,j,n) for(int i=j;i<n;i++)
#define r_frr(i,j,n) for(int i=n-1;i>=j;i--)
 
#define frrs(i,j,n,flag)    for(int i=j;i<n&&flag;i++)
#define r_frrs(i,j,n,flag)    for(int i=n-1;i>=j&&flag;i--)
 
#define arend(i,n) ((i!=n-1)?" ":"\n")
#define memset0(dp) memset(dp,0,sizeof(dp))
#define print_arr(begin,end)    for(auto it = begin;it!=end;it++)  cout<<*it<<arend(it,end);
#define log_this(name,value)    cout<<name<<": "<<value<<endl;
#define e4 10004
#define e5 100005
#define e6 1000006
#define e7 10000007
#define e9 1000000000
#define INF 9999999
using namespace std;
int     to_int(string s)    {stringstream ss;ss<<s;int a;ss>>a;return a;}
string  to_str(double a)    {stringstream ss;ss<<a;return ss.str();}
 
int a[1*e5];
 
int main(){
 
    cin.tie(0);
    //ios::sync_with_stdio(false);
    //cout<<setiosflags(ios::fixed)<<setprecision(0);
 
    //freopen("1.out","w",stdout);
 
    int t;
    while(cin>>t){
        while(t--){
            int n;cin>>n;
            fr(i,n) cin>>a[i];
            int lastw = -1;
            int noww = a[n-1];
            bool can = true;
            r_frr(i,1,n){
                if(a[i-1]>a[i]){
                    if(a[i]<lastw){
                        can = false;
                        break;
                    }
                    lastw = noww;
                    noww = a[i-1];
                }else{
                    if(a[i]-a[i-1]>1){
                        can = false;
                        break;
                    }
                }
            }
            if(can) cout<<"YES"<<endl;
            else    cout<<"NO"<<endl;
        }
    }
    
    return 0;
}

D. Nastya and Scoreboard

题意

有一个由火柴棍拼图组成的序列,询问加上 \(k\) 根火柴棍能够拼出的最大数字是多少。

解题

首先题面中有两个事情需要注意:

  • 输入拼图序列中存在非数字的情况;
  • \(k\) 个火柴可能不能够刚好让所有的拼图变成数字。

贪心+dfs,从大到小搜索可行情况,注意这里要用记搜,不然会超时。

既然记搜可过,看这个数据范围,估计也有dp的解法,等有时间再补上(挖坑+1

#include<bits/stdc++.h>
#define ll long long

#define fr(i,n) for(int i=0;i<n;i++)
#define frs(i,n,flag)   for(int i=0;i<n&&flag;i++)

#define frr(i,j,n) for(int i=j;i<n;i++)
#define r_frr(i,j,n) for(int i=n-1;i>=j;i--)

#define frrs(i,j,n,flag)    for(int i=j;i<n&&flag;i++)
#define r_frrs(i,j,n,flag)    for(int i=n-1;i>=j&&flag;i--)

#define arend(i,n) ((i!=n-1)?" ":"\n")
#define memset0(dp) memset(dp,0,sizeof(dp))
#define print_arr(begin,end)    for(auto it = begin;it!=end;it++)  cout<<*it<<arend(it,end);
#define log_this(name,value)    cout<<name<<": "<<value<<endl;
#define e4 10004
#define e5 100005
#define e6 1000006
#define e7 10000007
#define e9 1000000000
#define INF 9999999
using namespace std;
int     to_int(string s)    {stringstream ss;ss<<s;int a;ss>>a;return a;}
string  to_str(double a)    {stringstream ss;ss<<a;return ss.str();}

int n,k;
int ans[2005];
int cost[2005][10];
int preCan[2005][2005]; //记录[i+1,n)的元素能否使用j完美填充,-1未访问,0否,1是

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

int Cost(string org,string nto){
    int cost = 0;
    fr(i,7){
        int p = nto[i]-org[i];
        if(p<0){
            cost = -1;
            break;
        }else{
            cost+=p;
        }
    }
    return cost;
}

bool dfs(int i,int k){
    if(i==n&&k==0)  return preCan[i][k] = true;
    if(k<0 ||(i==n&&k>0))    return preCan[i][k] = false;

    r_frr(j,0,10){
        if(cost[i][j]!=-1){
            //cout<<i<<" "<<j<<" "<<cost[i][j]<<endl;
            ans[i] = j;
            bool hasf;
            int left = k-cost[i][j];
            if(preCan[i+1][left]==-1)   hasf = dfs(i+1,left);
            else hasf = preCan[i+1][left];

            if(hasf) return preCan[i][k] = hasf;
        }
    }
    return preCan[i][k] = false;;
}

int main(){

    cin.tie(0);
    //ios::sync_with_stdio(false);
    //cout<<setiosflags(ios::fixed)<<setprecision(0);

    while(cin>>n>>k){
        string inp;
        fr(i,n){
            cin>>inp;
            fr(j,10) cost[i][j] = Cost(inp,ITB[j]);
        }
        fr(i,n+1) fr(j,k+1) preCan[i][j] = -1;

        bool hasf = dfs(0,k);
        if(hasf){
            fr(i,n) cout<<ans[i];
            cout<<endl;
        }else{
            cout<<"-1"<<endl;
        }
    }

    return 0;
}
posted @ 2020-04-26 22:26  DOEMsy  阅读(440)  评论(0编辑  收藏  举报