Loading

24-3-2 个人赛




A - Last Train

难度: ⭐⭐⭐⭐

题目大意

现有n个车站, 每个车站都有6个属性, l, d, k, c, A, B; 从时刻l开始发车, 每隔时间d发一辆, 一共发k辆; 并且火车是从A点前往B点, 所需时间是c; 设F(x)指从车站x的车最晚什么时候出发可以到车站n;

解题思路

因为所有车站的目标都是n, 那么我们可以从车站n开始反向进行最短路dijkstra; 找到从v出发可以到达u的最晚的一班车; 如果v的l + c > F(u); 则说明从v来的车赶不上u的满足条件的最晚的那班车; 否则我们找的车次就是num = min((F(u) - (l + c)) / d, k - 1); 然后就可以用l + num * d来更新F(u);

神秘代码

#include<bits/stdc++.h>
#define int long long
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define endl '\n'
using namespace std;
const int N = 2e5 + 10, mod = 998244353, inf = 2e18;
typedef pair<int, int> PII;
int n, m, res;
string s;
struct node{
    int u, l, d, k, c;
};
node P[N];
vector<node> v[N];
int dis[N];
void dijkstra(){
    for(int i = 1; i <= n; i++) dis[i] = -inf;
    priority_queue<PII> heap;
    heap.push({inf, n});
    dis[n] = inf;
    while(heap.size()){
        PII t = heap.top();
        heap.pop();
        int id = t.second;
        for(auto x : v[id]){
            int y = dis[id] - (x.l + x.c); 
            if(y < 0) continue;
            int num = x.l + min(y / x.d, x.k - 1) * x.d;
            if(num > dis[x.u]){
                dis[x.u] = num;
                heap.push({dis[x.u], x.u});
            }
        }
    }
}
signed main(){
    cin >> n >> m;
    for(int i = 1; i <= m; i++){
        int l, d, k, c, a, b;
        cin >> l >> d >> k >> c >> a >> b;
        v[b].push_back({a, l, d, k, c});
    }
    dijkstra();
    for(int i = 1; i < n; i++){
        if(dis[i] == -inf) cout << "Unreachable" << endl;
        else cout << dis[i] << endl;
    }
	return 0;
}




B - Lucky bag

难度: ⭐⭐⭐⭐




C - Oil Deposits

难度: ⭐⭐

题目大意

给定一个n * n的矩阵, 矩阵中有若干个石油, 相邻的石油可看作一堆石油; 相邻是指上下左右以及对角线; 问该矩阵有多少堆石油;

解题思路

dfs板子题;

神秘代码

#include<bits/stdc++.h>
#define int long long
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define endl '\n'
using namespace std;
const int N = 1e6 + 10, mod = 998244353, inf = 1e18;
typedef pair<int, int> PII;
int n, m, cnt;
string s;
char g[200][200];
bool st[200][200];
int dx[] = {1, 0, -1, 0, 1, 1, -1, -1}, dy[] = {0, 1, 0, -1, 1, -1, 1, -1};
void dfs(int a, int b){
    st[a][b] = true;
    for(int i = 0; i < 8; i++){
        int x = a + dx[i], y = b + dy[i];
        if(x >= 1 && x <= n && y >= 1 && y <= m && (!st[x][y]) && g[x][y] == '@') dfs(x, y);
    }
}
signed main(){
    while(cin >> n >> m){
        if(n == 0 && m == 0) break;
        for(int i = 1; i <= n; i++){
            for(int j = 1; j <= m; j++){
                st[i][j] = false;
            }
        }
        for(int i = 1; i <= n; i++){
            for(int j = 1; j <= m; j++){
                cin >> g[i][j];
            }
        }
        int res = 0;
        for(int i = 1; i <= n; i++){
            for(int j = 1; j <= m; j++){
                if(g[i][j] == '@'){
                    if(!st[i][j]) {
                        dfs(i, j);
                        res++;
                    }
                }
            }
        }
        cout << res << endl;
    }
	return 0;
}




D - Add All

难度: ⭐⭐

题目大意

给定n个数, 可以任选两个数a, b相加得到新的数, 并且相加会有a + b的代价, 问如何相加可以让代价最小;

解题思路

哈夫曼树板子

神秘代码

#include<bits/stdc++.h>
#define int long long
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define endl '\n'
using namespace std;
const int N = 1e6 + 10, mod = 998244353, inf = 1e18;
typedef pair<int, int> PII;
int n, m, cnt;
string s;
int p[N];
signed main(){
    while(cin >> n){
        if(n == 0) break;
        priority_queue<int, vector<int>, greater<int>> heap;
        for(int i = 1; i <= n; i++){
            int a;
            cin >> a;
            heap.push(a);
        }
        int res = 0;
        while(heap.size() > 1){
            int a = heap.top();
            heap.pop();
            int b = heap.top();
            heap.pop();
            int c = a + b;
            res += c;
            heap.push(c);
        }
        cout << res << endl;
    }
	return 0;
}




E - German Conference for Public Counting

难度: ⭐⭐

题目大意

现在有很多个牌子, 牌子上有一个0~9之间的一个数字; 现在给定一个数n, 问我们至少需要多少个牌子可以把0~n中任意一个数表示出来; n为1e9;

解题思路

签到题, 对于n(n>1)位数的数, 一定存在一个n-1位的数是由同一个数组组成; eg: 0~23213中一定存在1111, 2222...10000; 所有0~9中每个数字的牌子都要至少准备n-1个; 而0~23213中还存在11111和22222, 所有再根据第n位的数遍历其他位的数就行; 复杂度最大为O(n)(n是位数, 最大为9)

神秘代码

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e5;
signed main() {
    string s;
    cin >> s;
    if (s.size() == 1) cout << s[0] - '0' + 1;
    else {
        int res = 10 * (s.size() - 1);
        res = res + (s[0] - '0') - 1;
        if (s[1] - '0' > s[0] - '0') res++;
        else if (s[1] - '0' == s[0] - '0') {
            bool f = true;
            for (int i = 1; i < s.size(); i++) {
                if (s[i] < s[0]) {
                    f = false;
                    break;
                }
            }
            if (f) res++;
        }
        cout << res;
    }
    return 0;
}




F - Eszett

难度: ⭐⭐

题目大意

给定一个由大写字母组成的字符串, 将其转化成小写字母输出, 然后在转换后我们可以将"ss"转化为B, 并且保证字符串中最多只有3个s; 输出所有可能的字符串, 无论顺序; 字符串长度最大为20, S最多出现3次;

解题思路

可以记一下string的replace函数: replace(下标, 长度, 字符串); 作用是用该字符串替换从下标开始的某长度的字符串; 返回值是修改后的字符串; 所以该函数相当于遍历了一遍字符串, 所以复杂度就是O(n);

神秘代码

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e5;
signed main() {
	string s;
	string res;
	cin >> s;
	for (int i = 0; i < s.size(); i++) s[i] = s[i] + 32;
	cout << s << endl;
	if (s.find("sss")!=-1) {
		cout << s.replace(s.find("sss"), 3, "Bs") << endl;
		cout << s.replace(s.find("Bs"), 2, "sB") << endl;
	}
	else if (s.find("ss") != -1) {
		cout << s.replace(s.find("ss"), 2, "B") << endl;	
	}
	return 0;
}




G - Yet Another Permutation Problem

难度: ⭐⭐

题目大意

定义一个长度为n的全排列数组, 其由1 ~ n的n个数字组成; 现在给定一个长度n, 要求输出一个长度为n的全排列数组, 对于该数组, Ai 和Ai+1可以得到一个最大公因数, 请问该数组怎么排列可以得到种类最多的最大公因数;

解题思路

对于数组x, 如果想要得到最大公因数x, 那么代价最小就是让其后面是2 * x; 利用这个贪心策略从1开始, 让其后面是前一个数的2倍, 直到新的数大于n;

神秘代码

#include<bits/stdc++.h>
#define int long long
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define endl '\n'
using namespace std;
const int N = 1e6 + 10, mod = 998244353, inf = 1e18;
typedef pair<int, int> PII;
int n, m, cnt;
string s;
bool st[N];
int p[N];
signed main(){
	int T;
    cin >> T;
    while(T--){
        cin >> n;
        for(int i = 1; i <= n; i++) st[i] = false;
        int idx = 0;
        for(int i = 1; i <= n; i++){
            if(st[i]) continue;
            p[++idx] = i;
            st[i] = true;
            int j = 2 * i;
            while(j <= n){
                st[j] = true;
                p[++idx] = j;
                j *= 2;
            }
        }
        for(int i = 1; i <= n; i++){
            cout << p[i] << ' ';
        }
        cout << endl;
    }
	return 0;
}
posted @ 2024-03-02 22:19  mostimali  阅读(9)  评论(0编辑  收藏  举报