Educational Codeforces Round 63 (Rated for Div. 2)

文章目录

  • A. Reverse a Substring(模拟)
  • B. Game with Telephone Numbers(思维)
  • C. Alarm Clocks Everywhere(模拟)
  • D. Beautiful Array(动态规划)


A. Reverse a Substring(模拟)

原题链接:http://codeforces.com/contest/1155/problem/A


题意: 给你一个字符串,求出是否存在子字符串在倒转后能使字符串的字典序变小,可以的话输出“YES”和子字符串的范围,不可以则输出“NO”。

思路: 直接暴力遍历,只要存在两个相邻字符的顺序从大到小排序即符合,否则不符合。


Code(C++):

#include 
using namespace std;
int main(){
    int n;  cin>>n;
    string str;
    cin>>str;
    for(int i=0;i<n;i++){
        if(str[i]<str[i-1]){
            cout<<"YES"<<endl<<i<<" "<<i+1<<endl;
            return 0;
        }
    }
    cout<<"NO"<<endl;
    return 0;
}


B. Game with Telephone Numbers(思维)

原题链接:http://codeforces.com/contest/1155/problem/B

题意: 给出一个数字序列(n>=11),有两个人任意删除数字,直到数字只剩下11位。如果删除后的数字串开头是8,那么就是第一个赢,输出“YES”;否则就是第二个人赢,输出“NO”。

思路: 从第一个数字开始找到第 n-10 个数字,如果8的数量大于非8的数量,则输出“YES”,否则输出“NO”。

注意:计算’8’的数量,要定义为char型,因为比较的是ASCII码值,所以不能直接定义为int型后直接比较。


Code(C++):

#include 
using namespace std;
char a[100100];
int main(){
    int n;  cin>>n;
    int sum1=0,sum2=0;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        if(i<=n-10){
            if(a[i]=='8')   sum1++;
            else    sum2++;
        }
    }
    if(sum1>sum2)
        cout<<"YES"<<endl;
    else
        cout<<"NO"<<endl;
    return 0;
}


C. Alarm Clocks Everywhere(模拟)

原题链接: http://codeforces.com/contest/1155/problem/C


题意: 给你 n 个事件开始时间和m个闹钟,对于每个闹钟,你可以定义第一个闹钟开始响的时间 y,然后它会每隔 p 分钟响一下,问是否能提醒到这 n 个事件,如果能请随意输出一组第一个闹钟开始的时间y和选择的间隔时间所在的位置 i 。

思路: 可想而知 y 就是第一个事件开始时间 x[0],然后求出这 n 个事件的所有间隔时间,找出他们的最大公约数,最后判断这个数是否能在 m 个间隔时间里找到,或者存在他的因子。


Code(C++):

#include 
#include 
using namespace std;
typedef long long ll;
const int N=3e5+100;
ll x[N],p[N],dif[N];

/*
ll gcd(ll a,ll b){
	return b==0?a:gcd(b,a%b);
}
*/

int main(){
    int n,m;
    cin>>n>>m;
    int k=1;
    for(int i=1;i<=n;i++){
        cin>>x[i];
        if(i!=1)
            dif[k++]=x[i]-x[i-1];
    }
    ll t=__gcd(dif[1],dif[2]);
    for(int i=3;i<n;i++){
        t=__gcd(t,dif[i]);
    }
    ll ans=0;
    for(int i=1;i<=m;i++){
        cin>>p[i];
        if(t%p[i]==0 && t>=p[i]){
            ans=i;
        }
    }
    if(ans)
        cout<<"YES"<<endl<<x[1]<<" "<<ans<<endl;
    else
        cout<<"NO"<<endl;
    return 0;
}


D. Beautiful Array(动态规划)

原题链接: http://codeforces.com/contest/1155/problem/D


题意: n个数,可以选择某个区间的数乘x,也可以不选,求乘完后的最大连续子段和。

思路: 把整个序列分成三种情况来dp:

  1. dp[0]=max(0ll,dp[0]+a),表示没有乘过x的子序列的最大值。
  2. dp[1]=max(dp[0],dp[1]+x*a),表示正在乘x的子序列的最大值。
  3. dp[2]=max(dp[1],dp[2]+a),表示已经乘完x的子序列的最大值。

注意,dp[0]里面要与0比较,因为是求连续子段和,而不是求子序列,子序列有可能不连续。


Code(C++):

#include 
using namespace std;
const int inf=0x3f3f3f3f;
typedef long long ll;
ll dp[3];
int main(){
    ll n,x;
    cin>>n>>x;
    ll ans=-inf,a;
    for(int i=1;i<=n;i++){
        cin>>a;
        dp[0]=max(0ll,dp[0]+a); //dp[0]表示没有乘过x的子序列的最大值,由于是连续子段,所以要与0比较
        dp[1]=max(dp[0],dp[1]+a*x); //dp[1]表示正在乘x的子序列的最大值
        dp[2]=max(dp[1],dp[2]+a);   //dp[2]表示已经乘完x的子序列的最大值
        ans=max(ans,dp[2]);
    }
    cout<<ans<<endl;
    return 0;
}


你可能感兴趣的:(Educational Codeforces Round 63 (Rated for Div. 2))