Acwing——第80场周赛

第一题

Acwing.4725 末尾字母
难度:easy

给定一个由大小写字母、空格和问号组成的字符串。

请你判断字符串中的最后一个字母是否是元音字母。

我们认为元音字母共有 6 个,分别为:A、E、I、O、U、Y(当然还有它们的小写)。

输入格式

一个由大小写字母、空格和问号组成的字符串。

保证问号在字符串中恰好出现一次,且一定出现在最后。

字符串中至少包含一个字母。

输出格式

如果字符串中的最后一个字母是元音字母,则输出 YES,否则输出 NO。

注意,我们问的是最后一个字母,而不是最后一个字符,空格和问号不算作字母。

数据范围

所有测试点满足,输入字符串的长度范围 [2,100]。

输入样例1:

Is it a melon?

输出样例1:

NO

输入样例2:

Is it an apple?

输出样例2:

YES

输入样例3:

Is it a banana ?

输出样例3:

YES

输入样例4:

Is it an apple and a banana simultaneouSLY?

输出样例4:

YES

代码:

#include<iostream>
#include<unordered_set>
using namespace std;

int main(){
    //先用一个哈希表来记录所有的元音字母
    unordered_set<char> uset;
    string vowel = "AEIOUYaeiouy";
    for(auto &c:vowel) uset.insert(c);
    
    //这里用getline来处理输入 cin遇到空格就会停止读取
    string s;
    getline(cin,s);
    
    //从倒数第二个字符开始遍历,遇到字母就退出
    int n = s.size();
    int i = n - 2;
    for(;i >= 0;i--){
        if(isalpha(s[i])) break;
    }
    //此时的s[i]就是最后一个字母,判断它是否为元音字母 输出结果
    if(uset.count(s[i])) puts("YES");
    else puts("NO");
    return 0;
}

时间复杂度:O(N)

第二题

Acwing.4276 寻找数字
难度:mid

给定一个正整数 n,请你找到一个正整数 x,要求:

  • x≥n
  • x 的各个数位均不包含 4 和 7 以外的数字,且 x 中包含的 4 的数量与 7 的数量恰好相等。
  • 满足前两个条件的前提下,x 应尽可能小。
输入格式

一个正整数 n。

输出格式

一个正整数,表示 x。

数据范围

前 6 个测试点满足 1≤n≤5000。
所有测试点满足 1≤n≤ 1 0 9 10^9 109

输入样例1:

4500

输出样例1:

4747

输入样例2:

47

输出样例2:

47

分析:
在这里插入图片描述

代码

#include<iostream>
#include<set>
using namespace std;
using LL = long long;
int n;
set<LL> s;

//注意:x的值是会超过int的最大值的,所以这里需要用 long long 来接收
void dfs(int u,LL x,int cnt){
    if(u > 10) return;
    //cnt 是4的个数 2 * cnt = u 说明7的个数和cnt相同 满足条件
    if(cnt * 2 == u)  s.insert(x);
    //cnt 只记录x 中 4的个数
    dfs(u + 1,x * 10 + 4,cnt+1);
    dfs(u + 1,x * 10 + 7,cnt);
}

int main(){
    cin>>n;
    dfs(0,0,0);
    LL ans = -1;
    //找出第一个大于n的数,即答案
    for(auto &x:s){
        if(x >= n){
            ans = x;
            break;
        }
    }
    cout<<ans<<endl;
    return 0;
}

时间复杂度:O( 2 m 2^m 2m)

第三题

Acwing.4727 摆放棋子
难度:hard

给定 n1 个完全相同的黑色棋子和 n2 个完全相同的白色棋子。

请你将所有棋子摆成一排。

在所有棋子都摆放好后,需满足:

不得有超过 k1 (即大于 k1)个黑色棋子连续相邻的排在一起。
不得有超过 k2 (即大于 k2)个白色棋子连续相邻的排在一起。
请问一共有多少种不同的摆放方法。

由于结果可能很大,你只需要输出对 1 0 8 10^8 108 取模后的结果。

输入格式

共一行,包含 4 个整数 n1,n2,k1,k2。

输出格式

输出满足要求的摆放方法数量对 1 0 8 10^8 108 取模后的结果。

数据范围

前 4 个测试点满足 1≤n1,n2≤10。
所有测试点满足 1≤n1,n2≤100,1≤k1,k2≤10。

输入样例1:

2 1 1 10

输出样例1:

1

输入样例2:

2 3 1 2

输出样例2:

5

输入样例3:

2 4 1 1

输出样例3:

0

分析:
在这里插入图片描述

dp代码

#include<iostream>
#include<algorithm>
using namespace std;
using LL =long long;

const int N = 105,M = 15,MOD = 1e8;
int f[N][N][M][M];
int n1,n2,k1,k2;

int main(){
    cin>>n1>>n2>>k1>>k2;
    f[0][0][0][0] = 1;
    
    for(int i = 0;i <= n1;i++){
        for(int j = 0;j <= n2;j++){
            for(int k = 0;k <= k1;k++){
                for(int u = 0;u <= k2;u++){
                    int v = f[i][j][k][u];
                    if(i+1<=n1&&k+1<=k1)f[i+1][j][k+1][0] = (f[i+1][j][k+1][0]+v)%MOD;
                    if(j+1<=n2&&u+1<=k2)f[i][j+1][0][u+1] = (f[i][j+1][0][u+1]+v)%MOD;
                }
            }
        }
    }
    LL ans = 0;
    for(int i = 0;i <= k1;i++) ans = (ans + f[n1][n2][i][0])%MOD;
    for(int i = 0;i <= k2;i++) ans = (ans + f[n1][n2][0][i])%MOD;
    
    cout<<ans<<endl;
    return 0;
}

时间复杂度为 O( N 2 N^2 N2 * K 2 K^2 K2)

记忆化搜索代码

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
using LL = long long;
const int MOD = 1e8,N = 105,M = 15;

int f[N][N][M][M];
int n1,n2,k1,k2;

int dfs(int u,int v,int w,int z){
    if(!u && !v) return 1;
    if(f[u][v][w][z] != -1) return f[u][v][w][z];
    LL sum = 0;
    if(u && w + 1 <= k1) sum = (sum + dfs(u-1,v,w+1,0))%MOD;
    if(v && z + 1 <= k2) sum = (sum + dfs(u,v-1,0,z+1))%MOD;
    f[u][v][w][z] = sum;
    return sum;
    
}

int main(){
    cin>>n1>>n2>>k1>>k2;
    memset(f,-1,sizeof f);
    cout<<dfs(n1,n2,0,0)<<endl;
    return 0;
}

时间复杂度为 O( N 2 N^2 N2 * K 2 K^2 K2)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值