SDUT 2021 Spring Individual Contest – A

2015 ICPC North American Qualifier Contest,原题链接

A – All about that base

题意

给你一个算式,问你这个算式中的数字在(1-36进制中)哪些进制下是合法的,输出所有合法的进制(10-35进制用a-z表示,36进制用0表示),否则输出invalid。只有满足所有数字的表示合法以及算式运算也合法才算合法。注意1进制此题规定只含有一个数字1,转换成十进制就是看有几个1(如1111表示十进制的4)。

分析

首先,数据的处理,可以按行读入然后按空格用字符串表示出每个数字和操作符。其次是进制转换,写个函数,转换成十进制来计算,进制转换过程中还要判断一下每位数字是否超过当前的进制。最后在十进制下判断算式是否正确。另外,本题要用longlong,1进制需要特殊处理,除法需要保证整除才算合法。

代码

#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int maxn = 1e5 + 10;
const double PI = acos(-1.0);
typedef pair<LL, LL> PII;

LL change(int base, string s, int &flag) {//进制转换+判断每位数字合法性
    LL num, ans = 0;
    LL now = 1;
    for (int i = s.size() - 1; i >= 0; i--) {
        int num;
        if (s[i] >= 'a' && s[i] <= 'z')
            num = s[i] - 'a' + 10;
        else
            num = s[i] - '0';
        if (num >= base) {
            flag = 1;
            break;
        }
        ans += num * now;
        now *= base;
    }
    return ans;
}

int main(int argc, char const *argv[]) {
    int t;
    cin >> t;
    getchar();
    while (t--) {
        string s;
        getline(cin, s);
        string a, b, c, op, now;
        int cnt = 0;//记录当前是第几个空格
        for (int i = 0; i < s.size(); i++) {
            if (s[i] == ' ') {
                cnt++;
                if (cnt == 1)
                    a = now;
                else if (cnt == 3)
                    b = now;
                else if (cnt == 2)
                    op = now;
                now.clear();
            } else {
                now += s[i];
            }
        }
        c = now;
        LL x, y, z;
        int f = 0, flag = 0;
        //特殊判断1进制是否合法
        for (int i = 0; i < a.size(); i++) {
            if (a[i] != '1') {
                flag = 1;
                break;
            }
        }
        for (int i = 0; i < b.size(); i++) {
            if (b[i] != '1') {
                flag = 1;
                break;
            }
        }
        for (int i = 0; i < c.size(); i++) {
            if (c[i] != '1') {
                flag = 1;
                break;
            }
        }
        if (flag == 0) {
            if (op[0] == '-' && a.size() - b.size() == c.size())
                printf("1"), f = 1;
            else if (op[0] == '+' && a.size() + b.size() == c.size())
                printf("1"), f = 1;
            else if (op[0] == '*' && a.size() * b.size() == c.size())
                printf("1"), f = 1;
            else if (op[0] == '/' && a.size() % b.size() == 0 &&
                     a.size() / b.size() == c.size())//除法要整除
                printf("1"), f = 1;
        }
        //判断2-36进制是否合法
        for (int i = 2; i <= 36; i++) {
            flag = 0;
            x = change(i, a, flag);
            y = change(i, b, flag);
            z = change(i, c, flag);
            if (flag == 1) continue;
            char ans;
            if (i == 36)
                ans = '0';
            else if (i >= 10)
                ans = 'a' + i - 10;
            else
                ans = '0' + i;
            if (op[0] == '+' && x + y == z)
                printf("%c", ans), f = 1;
            else if (op[0] == '-' && x - y == z)
                printf("%c", ans), f = 1;
            else if (op[0] == '*' && x * y == z)
                printf("%c", ans), f = 1;
            else if (op[0] == '/' && x % y == 0 && x / y == z)
                printf("%c", ans), f = 1;
        }
        if (f == 0)
            puts("invalid");
        else
            puts("");
        // puts("_____________");
        // cout << a << ' ' << b << ' ' << c <<endl;
    }
    return 0;
}

B – Bobby’s Bet(概率)

题意

两人打赌,对于一个S面的骰子,若投Y次出现至少X次大于面值等于R则赢W元,否则输1元,问你期望的回报是否大于1元。

分析

就是一道期望题,求出全部的期望即可,首先算出单次赢的概率是$(s – r + 1) / s$,输的概率是$(r-1)/s$可能的情况有赢x次,x+1次一直到y次,对于赢x次的概率即 $C_y^x* (win)^x*(lose)^{y-x}$,其中win表示单次赢的概率,lose表示单次输的概率,求出所有的概率相加即最终赢的概率,乘w就是期望和1比较大小即可。可以发现的是无论输赢的概率分母都是s,且每次求概率时win和lose的幂之和为y,那么对于每次概率如果不约分那么分母都是 $s^y$,所以只要计算出分子即可。组合数用递推预处理,幂运算写个快速幂即可,记得longlong。

代码

#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int maxn = 1e5 + 10;
const double PI = acos(-1.0);
typedef pair<LL, LL> PII;
int c[111][111];

void init() {
    c[0][0] = 1;
    for (int i = 1; i < 20; i++) {
        c[i][0] = 1;
        for (int j = 1; j < 20; j++) {
            c[i][j] = c[i - 1][j - 1] + c[i - 1][j];
        }
    }
}
LL qmi(LL a, LL b) {
    LL ans = 1;
    while (b) {
        if (b & 1) {
            ans *= a;
        }
        a *= a;
        b /= 2;
    }
    return ans;
}
int main(int argc, char const *argv[]) {
    int t;
    init();
    cin >> t;
    while (t--) {
        LL r, s, x, y, w;
        cin >> r >> s >> x >> y >> w;
        LL win = s - r + 1, lose = r - 1;
        LL mu = pow(s, y);
        LL ans = 0;
        for (LL i = x; i <= y; i++) {
            ans += 1.0 * qmi(win, i) * qmi(lose, y - i) * c[y][i] * 1.0;
        }
        ans = ans * w;
        if (ans <= mu)
            puts("no");
        else
            puts("yes");
    }
    return 0;
}

D – Circuit Counting(思维+DFS)

题意

给你n个向量,任选几个组成一个集合使得集合内向量和为0,求集合个数。

分析

由于n<=40,第一反应想到dfs爆搜,但是 $2^{40}$ 还是太大了,可以进行两次dfs,运用到一点记忆化的思想,先对前n/2个向量dfs枚举出所有可能,$dp[i][j]$ 记录集合的向量和为 $(i,j)$ 的集合数。再对后n/2个向量进行dfs,若集合的向量和为 $(x,y)$ ,则答案加上 $dp[-x][-y]$ ,由于负数不能作为下标,所以下标全部加上一个基数,保证全部为正数。

代码

#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int maxn = 1e3+10;
const double PI = acos(-1.0);
typedef pair<int, int> PII;
int n, m;
PII vec[maxn];
LL dp[maxn][maxn];
LL ans;
void dfs(int now, int x, int y) {
    if (now == m + 1) {
        dp[x + 500][y + 500]++;
        return;
    }
    dfs(now + 1, x, y);
    dfs(now + 1, x + vec[now].first, y + vec[now].second);
}
void dfs1(int now, int x, int y) {
    if (now == n + 1) {
        ans += (LL)dp[500 - x][500 - y];
        return;
    }
    dfs1(now + 1, x, y);
    dfs1(now + 1, x + vec[now].first, y + vec[now].second);
}

int main(int argc, char const *argv[]) {
    cin >> n;
    for (int i = 1; i <= n; i++) {
        cin >> vec[i].first >> vec[i].second;
    }
    m = n / 2;
    dfs(1, 0, 0);
    dfs1(m + 1, 0, 0);
    cout << ans - 1 << endl;
    return 0;
}

F – Quick Brown Fox(桶排)

题意

给你一串字符串,忽略大小写,问你a-z中有几个没出现过,若都出现过则输出“pangram”。

分析

写个桶排判断一下大小写,记录每个字符串出现的次数,遍历输出一遍即可。

代码

#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int maxn = 1e5+10;
const double PI = acos(-1.0);
typedef pair<int,int> PII;
string co = "Simon says ";
int tong[200];
int main(int argc, char const *argv[]) {
    int t;
    cin >> t;
    getchar();
    while(t--) {
        memset(tong,0, sizeof tong);
        string s;
        getline(cin, s);
        for(int i = 0; i < s.size(); i++) {
            if(s[i]>='a' && s[i] <= 'z') {
                tong[s[i]]++;
            }else if(s[i]>='A' && s[i] <= 'Z') {
                tong[s[i] + 32]++;
            }
        }
        vector<char> ans;
        for(int i = 'a'; i <= 'z'; i++){
            if(tong[i] == 0) {
                ans.push_back((char)i);
            }
        }
        if (ans.size() == 0) puts("pangram");
        else{
            cout << "missing ";
            for (int i = 0; i < ans.size(); i++) cout << ans[i];
            puts("");
        }
    }
    return 0;
}

H – Secret Message(签到)

题意

给你一串字符串,将其按从上到下,从左到右的顺序填入到一个M * M的矩阵中,M * M为大于等于字符串长度的最小值,多余的格子用“ * ”填满,然后将矩阵顺时针旋转90度,再按照从上到下从左到右的顺序输出字符串,忽略“ * ”。

分析

没啥好分析的,做就完事了。

代码

#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int maxn = 1e5+10;
const double PI = acos(-1.0);
typedef pair<int,int> PII;
char ans[1000][1000];
char chu[1000][1000];
int main(int argc, char const *argv[]) {
    int t;
    cin >> t;
    while(t--) {
        string s;
        cin >> s;
        int m = 1;
        while(m*m < s.size())m++;
        int now = 0;
        for(int i = 0; i < m; i++) {
            for(int j = 0; j < m; j++) {
                if(now < s.size()){
                    chu[i][j] = s[now++];
                }
                else chu[i][j] = '*';
            }
        }
        now = 0;
        for(int i = m-1; i >= 0; i--) {
            for(int j = 0; j < m; j++) {
                ans[j][now] = chu[i][j];
            }
            now++;
        }
        for(int i = 0; i < m; i++) {
            for(int j = 0; j < m; j++) {
                if(ans[i][j] != '*')
                printf("%c",ans[i][j]);
            }
        }
        puts("");
    }
    return 0;
}

I – Simon Says(签到)

题意

给你n个字符串,若某个字符串的最前面两个单词为“Simon says”则输出剩下的字符串,否则跳过。

分析

注意判断时必须判断“Simon says”后面还带个空格,若出现“Simon saysxxx”这样的不能输出。

代码

#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int maxn = 1e5+10;
const double PI = acos(-1.0);
typedef pair<int,int> PII;
string co = "Simon says ";
int main(int argc, char const *argv[]) {
    int t;
    cin >> t;
    getchar();
    while(t--) {
        string s;

        getline(cin, s);
        int f = 0;
        for(int i = 0; i < 11; i++) {
            if(s[i] != co[i]) {
                f = 1;
                break;
            }
        }
        if(!f) {
            for(int i = 11; i < s.size(); i++) cout << s[i];
            puts("");
        }
    }
    return 0;
}

J – Torn To Pieces(简单图论)

题意

告诉你每个站点和哪些站点相连,告诉你起点和终点,问你是否可以从起点走到终点,输出路径。

分析

比赛时读错题了,以为可能有多条路径,求最短路,就写了个Dijkstra记录路径,实际上直接bfs一遍就行了。另外站点是用字符串形式给出的,用unordered_map存一下下标就行了。

代码

#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int maxn = 1e5+10;
const double PI = acos(-1.0);
typedef pair<int,int> PII;
int cnt;
int t, st, ed;
unordered_map<string,int> id;
unordered_map<int,string> fan;
int get_id(string s) {
    if(id.count(s) == 0) {
        id[s] = ++cnt;
        fan[cnt] = s;
    }
    return id[s];
}
int mp[111][111], dis[111], path[111];
bool vis[111];
void dijkstra() {
    memset(dis, 0x3f, sizeof dis);
    memset(vis, 0, sizeof vis);
    dis[st] = 0;
    path[st] = -1;
    priority_queue<PII> q;
    q.push({0,st});
    while(q.size()) {
        int now = q.top().second;
        q.pop();
        if(vis[now]) continue;
        vis[now] = 1;
        for(int i = 1; i <= cnt; i++) {
            if(mp[now][i] == 1 && dis[i] > dis[now] + 1) {
                dis[i] = dis[now] + 1;
                path[i] = now;
                q.push({-dis[i],i});
            } 
        }
    }
}
int main(int argc, char const *argv[]) {
    cin >> t;
    string s;
    getchar();
    while(t--) {
        getline(cin, s);
        string now;
        int kong = 0;
        int x;
        for(int i = 0; i < s.size(); i++) {
            if(s[i] == ' ') {
                kong++;
                if(kong == 1) {
                    x = get_id(now);
                }
                else {
                    mp[x][get_id(now)] = 1;
                    mp[get_id(now)][x] = 1;
                }
                now.clear();
            }
            else now += s[i];
        }
        mp[x][get_id(now)] = 1;
        mp[get_id(now)][x] = 1;
    }
    getline(cin, s);
    string now;
    for (int i = 0; i < s.size(); i++) {
        if (s[i] == ' ') {
            st = get_id(now);
            now.clear();
        } else
            now += s[i];
    }
    ed = get_id(now);
    dijkstra();
    if(dis[ed] == 0x3f3f3f3f) puts("no route found");
    else {
        vector<string> ans;
        int now = ed;
        while(now != -1) {
            ans.push_back(fan[now]);
            now = path[now];
        }
        for(int i = ans.size() - 1; i>=0; i--) cout << ans[i] << ' ';
    }
    return 0;
}

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇