集训第二周

7.20

1.单词数

这题主要了解istringstream的用法,可以获取空格间的字符串 

int main() {
    set<string> s;
    string str;
    while (1) {
        getline(cin, str);
        s.clear();
        if (str == "#") break;

        //istringstream函数用于输入空格间的字符串
        istringstream iss(str);//要包含sstream头文件
        string word;
        while (iss >> word) {
            s.insert(word);
        }
        cout << s.size() << endl;
    }
    return 0;
}

2.丑数

一个丑数序列,丑数是质因数只能为2,3,5的数。质因数是能整除原数的素数

分析:原本我还用循环来一个个求丑数。。。但是时间复杂度太大肯定不行。(想想高手会用这么蠢的办法写吗,肯定不会,所以以后有些题一旦有了很暴力很挫的思路,就要多斟酌别的思路了)

所有丑数都是之前的丑数的倍数(2,3,5倍),然后利用set容器(因为能自动排序)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
set<ll>s;
int a[3]={2,3,5};
int main()
{
s.insert(1);
int id=1;
auto it=s.begin();
while(id<1500)
{
for(int i=0;i<3;i++) s.insert((*it)*a[i]);
id++;
it++;
}
cout << "The 1500'th ugly number is " << (*it) << ".\n";
}

3.简单计算

#include<math.h>
#include<stdlib.h>
#include<string>
#include <stdio.h>
#include<algorithm>
#include<iomanip>
#include<cmath>
#include<sstream>
#include<stack>
#include <utility>
#include<map>
#include <vector>
#include<iostream>
using namespace std;
//#include<bits/stdc++.h>
const int N = 1e6 + 10;
typedef long long ll;

int main() {
    string s;
    while (getline(cin, s) && s != "0") {
        stringstream str(s);
        string part_s;
        stack<double> st;
        //目标是把所有除了加号以外的计算都计算完毕,再把数据存入栈内,
        //最后全部加起来就可以了

        while (str >> part_s) {
            if (isdigit(part_s[0])) {
                //判断是否为数字,若是数字,直接存入栈内
                st.push(stod(part_s));
            }
            else {
                //是符号(注意,符号后的下一个必定是数字)
                if (part_s[0] == '+' || part_s[0] == '-') {
                    //若为加号,对下一个数据则不处理(因为要存到栈内都是加,目的已经达到了)
                    //若为减号,则将下一个数据乘以-1,再存入栈内
                    if (part_s[0] == '-') {
                        str >> part_s;//让part_s读取下一个数据
                        st.push(stod(part_s) * (-1));
                    }

                }
                else {
                    //若是*或/,涉及到该符号的前一个数据和后一个数据的计算

                    if (part_s[0] == '*') {
                        double front = st.top();

                        str >> part_s;
                        double behind = stod(part_s);

                        st.pop();//插入结果之前记得先把front的数据删了
                        st.push(front * behind);
                    }
                    else {
                        double front = st.top();

                        str >> part_s;
                        double behind = stod(part_s);

                        st.pop();//插入结果之前记得先把front的数据删了
                        st.push(front / behind);
                    }

                }
            }
        }

        double sum = 0;
        while (!st.empty()) {
            sum += st.top();
            st.pop();
        }
        printf("%.2f\n", sum);
    }
    return 0;
}

4.Shopping

这题没什么难的,主要是注意map的运用,例如insert的时候可以用上 make_pair ,还有可以通过类似 mp["memory"] ,的方法用键值查找数据

#include<string>
#include <stdio.h>
#include<algorithm>
#include<iomanip>
#include<cmath>
#include<sstream>
#include<stack>
#include <utility>
#include<map>
#include <vector>
#include<iostream>
using namespace std;
//#include<bits/stdc++.h>
const int N = 1e6 + 10;
typedef long long ll;

int main() {
    int n, m;
    while (cin >> n) {


        map<string, int> mp;//第一个元素是键值,靠键值来找
        string name;
        for (int i = 0; i < n; i++) {
            cin >> name;
            mp.insert(make_pair(name, 0));
        }
        cin >> m;

        for (int i = 0; i < m; i++) {
            //有m天
            for (int i = 0; i < n; i++) {
                int price;
                cin >> price >> name;
                auto it = mp.find(name);
                it->second += price;
            }

            int count = 0;
            for (auto it = mp.begin(); it != mp.end(); it++) {
                if (it->second > mp["memory"]) {
                    count++;
                }
            }
            cout << count + 1 << endl;
        }
        mp.clear();

    }
    return 0;
}

5.古老的密码

【题目描述】 古罗马帝国有一个拥有各种部门的强大政府组织。其中一个部门就是保密服务部门。为了保险起见,在省与省之间传递的重要文件中的大写字母是加密的。当时最流行的加密方法是替换和重新排列。 替换方法是将所有出现的字符按照一个规则替换,比如ABCDEFGHIJKLMNOPQRSTUVWXYZ到BCDEFGHIJKLMNOPQRSTUVWXYZA,如果原词是 "VICTORIOUS" 则它变成 "WJDUPSJPVT"。 排列方法改变原来单词中字母的顺序。例如:将顺序<2, 1, 5, 4, 3, 7, 6, 10, 9, 8>应用到 "VICTORIOUS" 上,则得到"IVOTCIRSUO"。 人们很快意识到单独应用替换方法或排列方法加密,都是很不保险的。但是如果结合这两种方法,在当时就可以得到非常可靠的加密方法。所以,很多重要信息先使用替换方法加密,再将加密的结果用排列的方法加密。用两种方法结合就可以将"VICTORIOUS" 加密成"JWPUDJSTVP"。 考古学家最近在一个石台上发现了一些信息。初看起来它们毫无意义,所以有人设想它们可能是用替换和排列的方法被加密了。人们试着解读了石台上的密码,现在他们想检查解读的是否正确。他们需要一个计算机程序来验证,你的任务就是写这个验证程序。 【输入描述】 输入有两行。第一行是石台上的文字。文字中没有空格,并且只有大写英文字母。第二行是被解读出来的加密前的文字。第二行也是由大写英文字母构成的。两行字符数目的长度都不超过100。 【输出描述】 如果第二行经过某种加密方法后可以产生第一行的信息,输出 "YES",否则输出"NO"

分析:题中阐述了两种加密方法,样例中给出的字符串可以只由其中一种方法加密,也可以两种加密方法都用上(这里也表明了,如果题目要求讲述不清晰,那么分析样例,结合样例理解题意,是很重要的)。

经分析发现,无论是用哪种方法,还是两种方法都用,一个加密后的字符串与未加密的字符串,共同点是如下:

例如字符串S1: ABBCDEE 经一次加密变成 CDDEFGG,

再经过一次加密变成字符串S2: DEDFCEG,

S1在哈希表中

S2在哈希表中

6.因子计算 

 两个数的积的因子,一定包括两个数各自的因子。然后经观察可以发现,剩下的元素是两个数各自因子相乘的结果。例如:

4*8 = 32,4最大的因子是4,8最大的因子是8,然后4的因子有1,2,4。8的因子有1,2,4,8。其中的元素分别相乘,必定不会大于32(不用担心数字过大)。而4又是8的因子,故4*4一定是32的因子

#include<iostream>
using namespace std;
#include<bits/stdc++.h>
const int N = 1e6 + 10;
typedef long long ll;

vector<ll> Calc(ll x) {
    vector<ll> ret;
    //超时,此处可优化
    for (int i = 1; i * i <= x; i++) {
        if (x % i == 0) ret.push_back(i), ret.push_back(x / i);
    }
    return ret;
}
int main() {
    ll a, b;
    cin >> a >> b;
    vector<ll> v1 = Calc(a);
    vector<ll> v2 = Calc(b);
    set<ll> ret;
    for (auto x1 : v1) {
        for (auto x2 : v2) {
            ret.insert(x1 * x2);
        }
    }
    cout << ret.size() << endl;
    cout << *ret.begin();
    for (auto it = ret.begin(); it != ret.end(); it++) {
        if (it == ret.begin()) continue;

        cout << " " << *it;
    }
    return 0;
}

7.21

几个小心得:

1.遇到一些数据量很大,容易超时的题目,可以尝试找规律。例如打表找规律,或者找是否有周期

2.题目中有公式,可以试着将公式变形,说不定有惊喜

3.要用不容易出错的写法,尽量少定义一些变量,不然乱七八糟容易出错(参考第4题)

4.想想高手会用这么蠢的办法写吗,肯定不会,所以以后有些题一旦有了很暴力很挫的思路,就要多斟酌别的思路了。千万不要吝啬思考的时间!!!不要急着写代码!!!

1. Fibonacci Again

 经典的打表找规律

using namespace std;
#include<iostream>
#include<stdio.h>
#include<queue>
using namespace std;
int main() {

    int n;
    //打表找规律
    while (cin >> n) {
        if (n % 4 == 2)cout << "yes" << endl;
        else cout << "no" << endl;
    }
    return 0;
}

2.Number Sequence

分析:这题其实还不理解,还需要搞搞清楚

#include <vector>
#include<iostream>
using namespace std;
const int N = 1e6 + 10;

typedef long long ll;
//int f[N];
int main() {
    int a, b, n;
    //对7取模,可以想到答案有周期
    while (1) {
        cin >> a >> b >> n;
        if (a == b && b == n && n == 0)break;
        vector<int> dp(60, 0);

        dp[1] = 1, dp[2] = 1;
        for (int i = 3; i <= 50; i++) {
            dp[i] = (a * dp[i - 1] + b * dp[i - 2]) % 7;
        }
        cout << dp[n % 49] << endl;
        
    }

    return 0;
}

3.Joseph

分析:约瑟夫环,用队列做超时了,那一定不能用循环了,所以只能用公式找出每次杀死的人,但公式原理还不清楚

#include<iostream>
#include<stdlib.h>
using namespace std;
 
int main()
{
    int k, s, j, m, n;
    int a[15] = {0};//存储k对应的循环变量m
    while (cin >> k)
    {
        if (k == 0) break;
        m = k;
        n = 2 * k;
        if (!a[k])//!a[k]==0
        {
            while(1)
            {
                s = 0;
                for (j = 0; j <k; j++)
                {//这个公式记得推导一下
                    s = (s + m - 1) % (n - j); //s是每次删除的位置
                    if (s < k) break;//如果删除的是小于k的数值,那么就不符合题意,直接开始下一个m的判断
                }
                if (j == k) break;
                m++;
            }
            a[k] = m;
        }		
        cout << a[k] << endl;
    }
    return 0;
}

4.All in All

题目不难,就是双指针

完美版

//这样才是好的代码,不容易出错,以后要注意用不容易出错的写法!!!
int main() {
    string s, myth;
    while (cin >> s >> myth) {
        int ps = 0, pm = 0;
        while (ps != s.size() && pm != myth.size()) {
            if (s[ps] == myth[pm]) {
                ps++, pm++;
            }
            else {
                pm++;
            }

        }
        if (ps == s.size() && pm <= myth.size()) {
            cout << "Yes" << endl;
        }
        else {
            cout << "No" << endl;
        }
    }
    
    return 0;
}

垃圾版

int main() {
    string s, myth;
    while (cin >> s >> myth) {
        int count = 0;//找到的字符
        int last = 0;//记录在myth中遍历的下标,但注意是在myth中找到符合的字符后才开始更新
        for (int ps = 0; ps < s.size(); ps++) {
            for (int pm = last; pm < myth.size(); pm++) {

                if (s[ps] == myth[pm]) {
                    count++;
                    last = pm + 1;
                    break;
                }
            }

            if (count != ps + 1) {
                
                break;
            }
        }

        if (count == s.size())cout << "Yes" << endl;
        else cout << "No" << endl;
    }
    
    return 0;
}

5.看病要排队

看病要排队这个是地球人都知道的常识。
不过经过细心的0068的观察,他发现了医院里排队还是有讲究的。0068所去的医院有三个医生(汗,这么少)同时看病。而看病的人病情有轻重,所以不能根据简单的先来先服务的原则。所以医院对每种病情规定了10种不同的优先级。级别为10的优先权最高,级别为1的优先权最低。医生在看病时,则会在他的队伍里面选择一个优先权最高的人进行诊治。如果遇到两个优先权一样的病人的话,则选择最早来排队的病人。

现在就请你帮助医院模拟这个看病过程。

Input

输入数据包含多组测试,请处理到文件结束。
每组数据第一行有一个正整数N(0<N<2000)表示发生事件的数目。
接下来有N行分别表示发生的事件。
一共有两种事件:
1:"IN A B",表示有一个拥有优先级B的病人要求医生A诊治。(0<A<=3,0<B<=10)
2:"OUT A",表示医生A进行了一次诊治,诊治完毕后,病人出院。(0<A<=3)

Output

对于每个"OUT A"事件,请在一行里面输出被诊治人的编号ID。如果该事件时无病人需要诊治,则输出"EMPTY"。
诊治人的编号ID的定义为:在一组测试中,"IN A B"事件发生第K次时,进来的病人ID即为K。从1开始编号。

Sample

InputcopyOutputcopy
 
7 IN 1 1 IN 1 2 OUT 1 OUT 2 IN 2 1 OUT 2 OUT 1 2 IN 1 1 OUT 1
 
2 EMPTY 3 1 1

分析:这题主要学习优先队列的用法,利用优先队列对自定义类型进行排序,然后按要求输出。其实可以只用结构体+qsort,但是比优先队列麻烦一些。注意要运算符重载!然后排序的方法是跟sort相反的! 

#include<queue>
#include<math.h>
#include<stdlib.h>
#include<string>
#include <stdio.h>
#include<algorithm>
#include<iomanip>
#include<cmath>
#include<sstream>
#include<stack>
#include <utility>
#include<map>
#include <vector>
#include<iostream>
using namespace std;
//#include<bits/stdc++.h>
//const int N = 1e6 + 10;
typedef long long ll;

struct Node {
    int pri;//优先级
    int num;//编号
};
//比较逻辑跟sort的不一样
bool operator<(Node a, Node b) {
    if (a.pri != b.pri) {
        return a.pri < b.pri;//降序
    }
    return a.num > b.num;//升序
}
int main() {
    int n;
    while (cin >> n) {
        priority_queue<Node> q[3];//创造三个医生队列
        int id = 1;//代表编号
        while (n--) {
            string s;
            cin >> s;
            int doctor, pri;
            
            if (s[0] == 'I') {
                cin >> doctor >> pri;
                struct Node node;
                node.pri = pri, node.num = id++;
                q[doctor - 1].push(node);
            }
            else {
                cin >> doctor;
                if (q[doctor - 1].empty()) {
                    cout << "EMPTY" << endl;
                }
                else {
                    cout << q[doctor - 1].top().num << endl;
                    q[doctor - 1].pop();
                }
            }
        }
    }

    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值