Week13

特殊正方形

输入n,输出n行n列的由+.组成的正方形,其中最外面一圈全是+,第二圈全是.,…,对于第i圈,如果i是奇数,那么全是+,否则全是.

输入格式

一行,一个整数n。

输出格式

n 行,为满足题目要求的正方形。注意不要有行末空格。

样例输入
10
样例输出
++++++++++
+........+
+.++++++.+
+.+....+.+
+.+.++.+.+
+.+.++.+.+
+.+....+.+
+.++++++.+
+........+
++++++++++
数据范围

对于100%的数据,保证2≤ n ≤100。

代码
#include<bits/stdc++.h>
using namespace std;

int main(){
    int n;
    char ans[105][105];
    cin >> n;
    for(int i = 0; i < n; ++i){  //循环n层
        if(i % 2 == 0){  //加号
            for(int j = i; j < (n - i); ++j){  //横
                ans[i][j] = '+';
                ans[n - i - 1][j] = '+';
            }
            for(int j = i; j < (n - i); ++j){
                ans[j][i] = '+';
                ans[j][n - i - 1] = '+';
            }
        }
        else{  //点
            for(int j = i; j < (n - i); ++j){
                ans[i][j] = '.';
                ans[n - i - 1][j] = '.';
            }
            for(int j = i; j < (n - i); ++j){
                ans[j][i] = '.';
                ans[j][n - i - 1] = '.';
            }
        }
    }
    for(int i = 0; i < n; ++i){
        for(int j = 0; j < n; ++j){
            cout << ans[i][j];
        }
			if(i != ( n - 1))
        	cout << endl;
    }
    //system("pause");
    return 0;
}

走楼梯2

楼梯有 n 阶,上楼可以一步上一阶,也可以一步上二阶。

但你不能连续三步都走两阶,计算走到第n阶共有多少种不同的走法。

输入格式

一行,一个数字,表示n。

输出格式

输出走楼梯的方式总数。

样例输入
6
样例输出
12
数据规模

对于100%100%的数据,保证n≤50。

代码
#include<bits/stdc++.h>
using namespace std;


int main(){
    int n;
    cin >> n;
    // 分三种情况:
    // 1. 一步登上第 i 级台阶
    // 2. 两步登上第 i 级台阶
    // 3. 连续两次两步登上第 i 级台阶
    vector<vector<long long>> stair(n + 1, vector<long long>(3));
    stair[0][0] = 1;
    for(int i = 1; i <= n; ++i){
        stair[i][0] = stair[i - 1][0] + stair[i - 1][1] + stair[i - 1][2];   
        if(i < 2)
            continue;
        stair[i][1] = stair[i - 2][0];
        stair[i][2] = stair[i - 2][1]; 
    }
    cout << stair[n][0] + stair[n][1] + stair[n][2] << endl;
    system("Pause");
    return 0;
}

走路

有一条很长的数轴,一开始你在00的位置。接下来你要走n步,第i步你可以往右走ai或者bi。

问n步之后,0到m的每个位置,能不能走到?

输入格式

第一行,两个整数n,m。

接下来n行,每行两个整数ai,bi,。

输出格式

一行,一共m+1个数,每个数都是01表示能否走到,数字之间不用空格隔开。

输入样例
3 10
1 2
2 6
3 3
输出样例
00000011001
数据规模

对于所有数据,保证1≤n≤100,1≤m≤105,1≤ai,bi≤100,1≤ m ≤105,1≤ai,bi≤1000

代码
#include<bits/stdc++.h>
using namespace std;

int dp[105][100005];  //表示第 i 步是否可以走到的 j 位置
int step[100005][2];  //第 i 步

int main(){
    int n, m;
    cin >> n >> m;
    for(int i = 1; i <= n; ++i){
        cin >> step[i][0] >> step[i][1];
    }
    memset(dp, 0, sizeof(dp));
    dp[0][0] = 1;  //第 0 个位置肯定可达
    for(int i = 1; i <= n; ++i){
        for(int j = 0; j <= m; ++j){
            if(dp[i - 1][j]){
                if(j + step[i][0] <= m)
                dp[i][j + step[i][0]] = 1;
            if(j + step[i][1] <= m)
                dp[i][j + step[i][1]] = 1;
            }
        }
    }
    for(int i = 0; i <= m; ++i)
        cout << dp[n][i];
    
    return 0;
}

简单分数统计

N� 个好朋友在codeforces上参加一场包含 M�个题目的比赛, 比赛期间codeforces网站一共有 k 次提交。

已知每个题目的分数,

但是由于他们只能查到在比赛期间codeforces总共的提交记录(其他用户提交的其他题目记录也包含在内, 即存在不属于该场比赛的题目),

所以想请你编写一个程序算出他们每个人的分数。

输入格式

第一行三个整数 N, M, K 分别表示好朋友的个数, 题目的个数, 和提交的总次数(其中0<N,M,K<=2000)。

接下来 N 行 第 i 行输入为第 i 个人的id,

接下来 M 行 第 j 行输入为第 j 个题目的名称和分数,

接下来 K 行 第 k 行输入为第 k 次提交的提交者id, 题目名称和结果(“WA” 或 “AC”, 如果"AC"代表通过这个题目, 提交者获得对应分数)。

注: 题目名称和id均为仅包含英文字母和数字的字符串, 题目分数为小于等于 1e6 的正整数. 每一行的多个输入之间用空格隔开。

所有输入的字符串长度 lengtℎ 满足 0<length≤500。

所有用户id和题目名称不存在重名, 用户AC了某个题之后之后不会再重复提交该题, 好朋友们只会提交属于比赛的题目。

输出格式

输出 N 行, 第 i 行输出第 i 个人的名字和对应分数 (名字和分数用空格隔开)。

样例输入
2 2 4
GabrielPessoa
beza
metebronca 100
geometry 200
beza metebronca AC
ffern numbertheory AC
GabrielPessoa geometry WA
beza geometry AC
样例输出
GabrielPessoa 0
beza 300
样例解释

beza 过了 metebronca和geometry 拿到 300300 分。

GabrielPessos 没有过题, 所以是 00 分。

还有一些其他选手提交的其他题目忽略不计

代码
#include<bits/stdc++.h>
using namespace std;

int main(){
    int N, M, K;  //好朋友的个数, 题目的个数, 和提交的总次数
    cin >> N >> M >> K;
    map<string, int> score;  //记录每个人以及其对应的分数
    map<string, int> q;  //记录每道题以及对应的分数
    map<string, map<string, int>> answered;  //记录是否已经作答过
    string name[205];
    for(int i = 0; i < N; ++i){
        cin >> name[i];
    }
    for(int i = 0; i < M; ++i){
        string s;
        int a;
        cin >> s >> a;
        q.emplace(s, a);
    }
    for(int i = 0; i < K; ++i){
        string s1, s2, s3;
        cin >> s1 >> s2 >> s3; 
        //cout << "s1: " << s1 << " s2: " << s2 << " s3: " << s3 << endl;
        if(s3 == "AC" && !answered[s1][s2]){
            answered[s1][s2] = 1;
            //cout << "YES" << endl;
            score[s1] += q[s2];
        }       
    }
    // map<string, int>::reverse_iterator x;
    // for(x = score.rbegin(); x != score.rend(); ++x)
    //     cout << x->first << " " << x->second << endl;
    for(int i = 0; i < N; ++i)
        cout << name[i] << " " << score[name[i]] << endl;
    //system("pause");
    return 0;
}

Alice的德州扑克

德州扑克是目前世界上最流行的扑克游戏,全世界有众多相关的比赛,例如是 WSOP,WPT,EPT等,也让这款游戏的玩法变得层出不穷,丰富多变。 不要被简单的游戏规则而误导,复杂多变的比赛状况,让这款游戏在高水平的竞技中会变得非常复杂,这也让人们为德州扑克给出了这样一句评价 ”用一刻就能学会,但要用一生才能掌握” 。

现在我们并不在乎游戏规则是什么,因为 Alice 是一个德州扑克高手,他对于德州扑克的规则烂熟于心,不过他每次都记不得牌型的大小关系,他知道你是一个编程高手,所以他想让你帮他写一个程序:输入五张牌的大小和花色,输出这五张牌能组成的最大牌型.你能帮帮他吗?

为了降低你的编程难度,我们规定:

  1. 输入的牌都是来源于同一副扑克牌
  2. 输入的牌的点数都是非递减的
  3. 所有花色没有大小之分

下面给出各牌型,(从大到小)

  1. 皇家同花顺(ROYAL FLUSH):五张顺连的牌(点数连续单调递增),且最大的一张牌是A(Ace),并且五张牌的花色相同
  2. 同花顺(STRAIGHT FLUSH):五张顺连的牌(点数连续单调递增),不规定最大的一张牌是A(Ace),并且五张牌的花色相同
  3. 四条(FOUR OF A KIND):至少四张牌的点数相同
  4. 葫芦(FULL HOUSE):至少三张牌的点数相同,并且除此之外还有两张牌的点数相同
  5. 同花(FLUSH):五张牌的花色都相同
  6. 顺子(STRAIGHT):五张顺连的牌(点数连续单调递增),不要求五张牌的花色相同
  7. 特别注意:由于 Alice 是个谨慎的人,所以比 三条(THREE OF A KIND) (包括三条) 小的牌型 Alice 不在乎他们的大小关系,你只需要告诉 Alice 弃牌就行
输入格式

输入两行,每行五个数字,第一行的第 i 个字符表示第 i 张扑克的点数,

第二行的第 i 个数字表示第 i 张扑克花色。(保证输入的牌的点数是非递减的,且所有输入均合法)

点数和对应输入的数字:

  • 2−102−10 对应 2 - 10
  • J(Jack) 对应 11
  • Q(Queen) 对应 12
  • K(King) 对应 13
  • A(Ace)对应 14

花色和对应输入的数字:

  • 黑桃 (Spades) 对应 1
  • 方片 (Diamonds) 对应 2
  • 红桃 (Hearts) 对应 3
  • 梅花 (Clubs) 对应 4
输出格式

输出这五张牌能组成的最大牌型。

  • 如果最大是皇家同花顺输出 “ROYAL FLUSH”
  • 如果最大是同花顺输出 “STRAIGHT FLUSH”
  • 如果最大是四条输出 “FOUR OF A KIND”
  • 如果最大是葫芦输出 “FULL HOUSE”
  • 如果最大是同花输出 “FLUSH”
  • 如果最大是顺子输出 “STRAIGHT”
  • 如果最大的牌型小于等于三条输出"FOLD",劝 Alice 弃牌
  • 输出不包括引号
样例输入1
10 11 12 13 14
1 1 1 1 1
样例输出1
ROYAL FLUSH
样例输入2
10 11 12 13 14
1 2 1 3 4
样例输出2
STRAIGHT
样例输入3
6 6 6 7 7
1 2 3 1 3
样例输出3
FULL HOUSE
样例输入4
3 3 6 6 9
1 2 1 2 1
样例输出4
FOLD
代码
#include<bits/stdc++.h>
using namespace std;

int main(){
    int type = -1;
    int color[5], card[5];  //花色以及牌
    //输入
    for(int i = 0; i < 5; ++i)
        cin >> card[i];
    for(int i = 0; i < 5; ++i)
        cin >> color[i];
    //判断顺子
    if(card[1] == (card[0] + 1) && card[2] == (card[1] + 1) && card[3] == (card[2] + 1) && card[4] == (card[3] + 1)){
        if(color[0] == color[1] && color[1] == color[2] && color[2] == color[3] && color[3] == color[4]){  //同花顺
            if(card[4] == 14){  //皇家同花顺
                type = 1;
            }
            else
            {
                type = 2;
            }
                
        }
        else
        {
            type = 6;
        }
            
    }
    else
    {
        if(card[0] == card[3] || card[0] == card[4] || card[1] == card[4]){  //四条
            type = 3;
        }
        else if((card[0] == card[2] && card[3] == card[4]) || (card[2] == card[4] && card[0] == card[1])){  //葫芦
            type = 4;
        }
        else if(color[0] == color[1] && color[1] == color[2] && color[2] == color[3] && color[3] == color[4]){  //同花
            type = 5;
        }

    }
    switch (type)
    {
    case -1:
        cout << "FOLD";
        break;
    case 1:
        cout << "ROYAL FLUSH";
        break;
    case 2:
        cout << "STRAIGHT FLUSH";
        break;
    case 3:
        cout << "FOUR OF A KIND";
        break;
    case 4:
        cout << "FULL HOUSE";
        break;
    case 5:
        cout << "FLUSH";
        break;
    case 6:
        cout << "STRAIGHT";
        break;
    }
    //system("pause");
    return 0;
}

订单编号

小缘开了一家公司,生意很好,每天都会收到很多订单,自动交易系统会自动给这些订单生成没有重复的订单编号。但是有一天,系统出现了未知的错误,导致当天的订单编号可能有重复的,这可把小缘急坏了。你可以帮助小缘按照规则给这些订单重新编号吗?

按照时间先后顺序给出 N 个正整数作为原订单编号,你需要按照规则依次赋予这些订单新的编号,对于任意一个订单,要找到大于等于其原订单编号且未被使用过的(没有被之前的订单作为新的订单编号)的最小整数,作为它的新订单编号。

例如: 原订单编号依次为1 2 3 1,则新订单编号应该为1 2 3 4 (前3个订单的原订单编号都没有使用过,所以用其原订单编号即可,对于第四个订单,原订单编号为1,而1, 2, 3都已经被使用过,所以新订单编号为4)。

输入格式

第一行输入一个整数 N (1≤N≤5×105)(1≤5×105)。

第二行输入 N 个数 ai(1≤ai≤109)(1≤109) 作为原订单编号。

输出格式

输出一行,包含 N 个整数为新的订单编号。

样例输入1
6
2 3 4 1 1 1
样例输出1
2 3 4 1 5 6
样例输入2
3
1000000000 1000000000 1000000000
样例输出2
1000000000 1000000001 1000000002
样例输入3
6
4 5 1 2 1 1
样例输出3
4 5 1 2 3 6
代码
#include<bits/stdc++.h>
using namespace std;

set<pair<int, int>> s;  //存一个一个的区间,并且会根据 pair 的第二个参数来从小到大排序

void insert(int l, int r){
    if(l > r)
        return;
    else
        s.insert(make_pair(r, l));
}

int main(){
    int n, x;
    scanf("%d", &n);
    insert(1, 2e9);  //反过来插入,插入一个 1 -- 2e9 的区间
    for(int i = 1; i <= n; ++i){
        scanf("%d", &x);
        auto it = s.lower_bound(make_pair(x, 0));  //寻找下限
        int res = max(x, it->second);
        insert(it->second, res - 1);
        insert(res + 1, it->first);
        printf("%d ", res);
        s.erase(it);
    }
    //system("pause");
    return 0;
}

饿饿 饭饭

有n个同学正在排队打饭,第i个同学排在从前往后第i个位置。但是这天食堂内只有一个食堂阿姨,为了使同学们都能尽快的吃上饭,每一个同学在打完一份饭之后就会排在队伍的末尾先吃着打到的饭,我们知道第i个同学的饭量为ai,也就是说第i个同学要吃ai份饭才能吃饱,当一位同学吃饱后,他就会立刻离开食堂,不会排在队伍的末尾。食堂阿姨想知道,在打完k份饭之后,队伍的样子是怎样的,但是食堂阿姨数学不太好,想让你帮忙想想办法。

输入格式

第一行给出两个整数n,k。

第二行给出n个整数a1,a2,…an1,2,…。

输出格式

如果食堂阿姨打饭数少于k,请输出"-1"。

否则按照队伍顺序输出每一个同学的编号。

样例输入1
3 3
1 2 1
样例输出1
2
样例输入2
4 10
3 3 2 1
样例输出2
-1
样例输入3
7 10
1 3 3 1 2 3 1
样例输出3
6 2 3
数据规模

数据保证1≤n≤105, 0≤k≤1014, 1≤ai≤109。

代码
 #include<bits/stdc++.h>
using namespace std;

int a[100005] = {0};
int c[100005] = {0};  //到第 i + 1 轮的时候还有哪些人在队列里
int n;
long long k, s = 0;

long long cal(int m){  //前 m 轮打多少份饭
    long long res = 0;
    for(int i = 1; i <= n; ++i){
        if(a[i] <= m)
            res += a[i];
        else
            res += m;
    }
    return res;
}

int main(){
   
    scanf("%d %lld", &n, &k);
    for(int i = 1; i <= n; ++i){
        scanf("%d", &a[i]);
        s += a[i];
    }
    if(s < k){
        printf("-1");
        return 0;
    }
    int l = 0, r = 1e9;
    while(l + 1 < r){
        int m = (l + r) / 2;
        if(cal(m) <= k)
            l = m;
        else
            r = m;
    }  //最后得到打了 l 轮饭
    k -= cal(l);  //最后还剩多少份饭
    int tot = 0;  //最后还有多少人
    for(int i = 1; i <= n; ++i){
        if(a[i] > l)
            c[++tot] = i;
    }
    for(int i = k + 1; i <= tot; ++i){  //打完还没够的人在开头
        printf("%d ", c[i]);
    }
    for(int i = 1; i <= k; ++i){
        if(a[c[i]] != l  + 1)
            printf("%d ", c[i]);  // 打完饭会走到末尾
    }
    //system("pause");
    return 0;
}

任务分配

你有n个任务,其中第i个任务,在si开始,ei时刻结束,如果做这个任务,你能获得wi的收益。

但是你在一个时刻只能做一个任务,问选择哪些任务,能让你的收益尽量大。

注意:你在上一个任务结束后马上开始下一个任务是可以的。

输入格式

第一行一个整数n。

接下来n行,每行三个整数si,ei,wi�。

输出格式

一个数,表示答案。

样例输入

3
1 3 100
2 4 199
3 5 100

样例输出

200

数据规模

对于所有数据,保证1≤n≤103,1≤si<ei≤103,1≤wi≤105。

代码
#include<bits/stdc++.h>
using namespace std;

const int maxn = 1005;
int n, dp[maxn] ={0};
struct m{
    int s, e, w;
}a[maxn];

bool cmp(m x, m y){  //从小到大排序
    if(x.e == y.e)
        return x.s < y.s;
    else
        return x.e < y.e;
}

int main(){
    int ans = -1;
    scanf("%d", &n);
    for(int i = 1; i <= n; ++i){
        scanf("%d%d%d", &a[i].s, &a[i].e, &a[i].w);
    }
    sort(a + 1, a + 1 + n, cmp);
    for(int i = 1; i <= n; ++i){  //遍历所有任务
        for(int j = 0; j <= i; ++j){  //只用遍历到 i 因为我们已经对任务数组进行了排序
            if(a[j].e <= a[i].s){  //结束点小于当前任务的开始点
                dp[a[i].e] = max(dp[a[i].e], dp[a[j].e] + a[i].w);
                ans = max(ans, dp[a[i].e]);
            }
        }
    }
    printf("%d", ans);
    //system("pause");
    return 0;
}

路径计数

有一个n×n的网格,有些格子是可以通行的,有些格子是障碍。

一开始你在左上角的位置,你可以每一步往下或者往右走,问有多少种走到右下角的方案。

由于答案很大,输出对109+7109+7取模的结果。

输入格式

第一行一个正整数n。

接下来n行,每行n个正整数,11表示可以通行,00表示不能通行。

输出格式

一个整数,表示答案。

样例输入
3
1 1 1
1 0 1
1 1 1
样例输出
2
数据规模

对于100%100%的数据,保证2≤n≤100,左上角右下角都是可以通行的。

代码
#include<bits/stdc++.h>
using namespace std;
const int maxn = 105;
const int m = 1000000007;
int n;
int g[maxn][maxn];
int dp[maxn][maxn];

int main(){
    memset(g, 0, sizeof(g));
    memset(dp, 0, sizeof(dp));
    scanf("%d", &n);
    for(int i = 1; i <= n; ++i){
        for(int j = 1; j <= n; ++j){
            scanf("%d", &g[i][j]);
        }
    }
    dp[1][1] = 1;
    for(int i = 1; i <= n; ++i){
        for(int j = 1; j <= n; ++j){
            if(g[i][j] == 1){
                if(i == 1 && j == 1)
                    continue;
                dp[i][j] = (dp[i - 1][j] + dp[i][j - 1]) % m;
            }
        }
    }
    // for(int i = 0; i <= n; ++i){
    //     for(int j = 0; j <= n; ++j){
    //         printf("%d ", dp[i][j]);
    //     }
    //     printf("\n");
    // }
    printf("%d", dp[n][n]);
    //system("pause");
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值