Acwing 第33场周赛

1、判断数字

给定一个整数 n,请你统计其各位数字中 4 和 7 的出现次数。

如果 4 的出现次数加上 7 的出现次数恰好等于 4 或 7,则输出 YES,否则输出 NO。

例如,当 n=40047 时,4 出现了 2 次,7 出现了 1 次,2+1=3,既不是 4 也不是 7,因此,输出 NO;当 n=7747774 时,4 出现了 2 次,7 出现了 5 次,2+5=7,因此,输出 YES。

输入格式
一个整数 n。

输出格式
一行,YES 或者 NO。

数据范围
所有测试点满足 1≤n≤10^18。

输入样例1:
40047
输出样例1:
NO
输入样例2:
7747774
输出样例2:
YES

1、分析

简单模拟

2、代码

#include<iostream>
using namespace std;
typedef long long ll;
int main()
{
    ll n;
    int num_4 = 0,num_7 = 0;
    cin >> n;
    while(n)
    {
        if(n % 10 == 4) num_4 ++;
        if(n % 10 == 7) num_7 ++;
        n /= 10;
    }
    if(num_7 + num_4 == 4 || num_4 + num_7 == 7) cout << "YES";
    else cout << "NO";
}

2、最长合法括号子序列

一个合法的括号序列满足以下条件:

序列()被认为是合法的。
如果序列X与Y是合法的,则XY也被认为是合法的。
如果序列X是合法的,则(X)也是合法的。
例如,(),()(),(())这些都是合法的。

现在,给定一个由 ( 和 ) 组成的字符串。

请你求出其中的最长合法括号子序列的长度。

注意,子序列不一定连续。

输入格式
共一行,一个由 ( 和 ) 组成的字符串。

输出格式
一个整数,表示最长合法括号子序列的长度。

数据范围
前五个测试点满足, 1≤输入字符串的长度≤10。
所有测试点满足,1≤输入字符串的长度≤10^6。

输入样例1:
(()))(
输出样例1:
4
输入样例2:
()()(()(((
输出样例2:
6

1、分析

利用栈进行处理

2、代码

#include<stack>
#include<iostream>
#include<cstring>
using namespace std;
stack<char> s;
int main()
{
    string n;
    cin >> n;
    int res = 0;
    for(int i = 0; i < n.size(); i ++)
    {
        if(n[i] == '(')  s.push(n[i]);
        else if(n[i] == ')') 
        {
           if(!s.empty())
           {
               s.pop();
               res += 2;
           }
        }
    }
    cout << res;
}

3、电话号码

一个电话销售员正在整理他的电话簿。

电话簿中记录了他的全部客户的电话号码。

一个客户可能有不止一个电话号码。

不同客户可能拥有完全相同的电话号码。

电话簿中一共包含 n 条记录。

每条记录都是首先包含一个字符串,表示客户的姓名,然后包含一个整数,表示本条记录包含的电话号码数量,最后是本条记录所包含的电话号码。

不同客户的姓名两两不同,所以如果两条记录包含的客户姓名相同,那么我们认为这都是记录的同一人的电话信息。

同一记录中可能包含相同的电话号码,不同记录中也可能包含相同的电话号码。

在进行整理时,应遵守如下原则:

如果一个客户拥有多条记录,则需要将这些记录进行合并,每人只保留一条记录,去记录他的全部有效号码。
如果一个客户记录的多个电话号码完全相同,则只保留一个作为有效号码,其余的全部视为无效号码。
如果一个客户记录的两个不同电话号码 a 和 b 满足 a 是 b 的后缀,则号码 a 视为无效号码。
请输出整理后的电话记录。

输入格式
第一行包含整数 n,表示记录数量。

接下来 n 行,每行描述一条记录,首先包含一个长度不超过 10 的由小写字母构成的非空字符串,表示客户姓名,然后包含一个不超过 10 的正整数,表示本条记录包含的号码数量,最后包含本条记录的所有号码,每个号码都是长度不超过 10 的由数字构成的非空字符串,可能包含前导 0。

输出格式
首先输出一个整数 m,表示完成整理后的记录数量。

接下来 m 行,每行输出一条记录信息,格式要求与输入一致。

同一行的数据之间用单个空格隔开。

记录的先后顺序随意,一条记录中的号码顺序随意。

数据范围
前三个测试点满足 1≤n≤4。
所有测试点满足 1≤n≤20。

输入样例1:
2
i 1 00123
m 1 00123
输出样例1:
2
m 1 00123
i 1 00123
输入样例2:
3
l 2 612 12
p 1 12
k 1 612
输出样例2:
3
k 1 612
p 1 12
l 1 612
输入样例3:
4
i 3 123 123 456
i 2 456 456
i 8 789 3 23 6 56 9 89 2
d 2 23 789
输出样例3:
2
d 2 23 789
i 4 789 123 2 456

1、分析

大模拟,用好stl工具进行适当处理即可

2、代码

#include<iostream>
#include<unordered_map>
#include<vector>
#include<cstring>
#include<algorithm>
using namespace std;
//key为用户名,value为用户的所有电话号码
unordered_map<string,vector<string> > mp;

int main()
{
    int n;
    cin >> n;
    // 存储有效的用户数量
    int resnum = 0;
    for(int i = 0; i < n; i ++)
    {
        string name;
        int num;
        cin >> name >> num;
        for(int i = 0; i < num; i ++)
        {
            string phone;
            cin >> phone;
            if(mp[name].size() == 0) resnum ++;
            mp[name].push_back(phone);
        }
    }
    cout << resnum << endl;
    for(auto p : mp)
    {
        auto nums = p.second;
        //先排序,用于后面unique去重
        sort(nums.begin(),nums.end());
        //由于前面排序了,所有重复的电话现在都相连,unique去除所有连续的重复电话
        nums.erase(unique(nums.begin(),nums.end()),nums.end());
        //判断所有不重复的电话,是否相互为后缀(感觉可以优化)
        for(auto n = nums.begin(); n != nums.end(); n ++)
        {
            bool ifsub = false;
            for(auto m = nums.begin(); m != nums.end() && !ifsub; m ++)
            {
                if((*n).length() <(*m).length())
                {
                    bool issub = true;
                    for(int i = (*n).size() - 1,j = (*m).size() - 1; i >= 0; i --,j --)
                    {
                      if((*m)[j] != (*n)[i]) 
                      {
                        issub = false;
                        break;
                      }
                    }
                    if(issub)
                    {
                       ifsub = issub;
                       nums.erase(n); 
                       n --;
                    }
                }
            }
        }
        cout << p.first << " " << nums.size();
        for(int i = 0; i < nums.size(); i ++)
        {
            cout << " " << nums[i];
        }
        cout << endl;
    }
    
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值