【CCF CAT 】全国算法精英大赛2024年2月1日

赛时我们通过了7题,排名25。

A 摩斯电码

队友代码

#include<bits/stdc++.h>
using namespace std;
#define int long long
typedef pair<int, int> P;


map<string, string> mp;

void solve () {
    mp["01"] = "A";
    mp["1000"] = "B";
    mp["1010"] = "C";
    mp["100"] = "D";
    mp["0"] = "E";
    mp["0010"] = "F";
    mp["110"] = "G";
    mp["0000"] = "H";
    mp["00"] = "I";
    mp["0111"] = "J";
    mp["101"] = "K";
    mp["0100"] = "L";
    mp["11"] = "M";
    ///////
    mp["10"] = "N";
    mp["111"] = "O";
    mp["0110"] = "P";
    mp["1101"] = "Q";
    mp["010"] = "R";
    mp["000"] = "S";
    mp["1"] = "T";
    mp["001"] = "U";
    mp["0001"] = "V";
    mp["011"] = "W";
    mp["1001"] = "X";
    mp["1011"] = "Y";
    mp["1100"] = "Z";
    ///////
    mp["01111"] = "1";
    mp["00111"] = "2";
    mp["00011"] = "3";
    mp["00001"] = "4";
    mp["00000"] = "5";
    mp["10000"] = "6";
    mp["11000"] = "7";
    mp["11100"] = "8";
    mp["11110"] = "9";
    mp["11111"] = "0";
    mp["001100"] = "?";
    mp["10010"] = "/";
    mp["101101"] = "()";
    mp["100001"] = "-";
    mp["010101"] = ".";

    string s;
    cin >> s;
    vector<string> v;
    for(int i = 0; i < s.size(); i++) {
        string t;
        int j = i;
        while(j < s.size() && s[j] != '.') {
            t += s[j];
            j ++ ;
        }
        // cout << t << ": " << mp[t] << endl;
        v.emplace_back(mp[t]);
        i = j;
    }
    for(auto & x : v) {
        cout << x;
    }
}
signed main () {
    solve ();
    return 0;
}

B 光线折射

多画一画,多特批一下就行了

#include <bits/stdc++.h>

using namespace std;

using i32 = int32_t;
using i64 = long long;

#define int i64

i32 main() {
    int n, m;
    cin >> n >> m;
    int d, x = 0, y = 0;
    if (n < m) {
        x = n, y = n;
        d = min(n, m - n);
        x -= d, y += d;
        if (x != 0) y -= x, x = 0;
        else if (x == 0 and y == m) x += d, y -= d;
        else {
            d = min(n, m - y);
            x += d, y += d;
        }
    } else if (n > m) {
        x = m, y = m;
        d = min(n - m, m);
        x += d, y -= d;
        if (y != 0) {
            x -= y, y = 0;
        } else if (x == n and y == 0) x -= d, y += d;
        else {
            d = min(m, n - x);
            x += d, y += d;
        }
    } else x = n, y = m;
    cout << x << " " << y << "\n";
    return 0;
}

C 多项式还原

题目保证了有唯一解,所以可以把\(m\)转换成\(n+1\)进制数。这个思路是队友想的。

#include <bits/stdc++.h>

using namespace std;

using i32 = int32_t;
using i64 = long long;

#define int i64

using vi = vector<int>;

i32 main() {
    ios::sync_with_stdio(false), cin.tie(nullptr);
    int n, m;
    cin >> n >> m;
    int t = n + 1;
    vi a;
    while (m)
        a.push_back(m % t), m /= t;
    int f = 0;
    for (int i = a.size() - 1; i >= 0; i--) {
        if (a[i] == 0) continue;
        if (f == 1) cout << "+";
        else f = 1;
        if (a[i] != 1 or i == 0) cout << a[i];
        if (i == 1) cout << "x";
        else if (i > 1) cout << "x^" << i;
    }
    return 0;
}

D 开心消消乐

\(n,m\)都很小,所以可以直接暴力搜索。为了方便处理,我把整个图旋转一下,来改变重力的方向。

对于当前的状态,直接bfs染色,同时统计每种颜色出现的次数。然后枚举每个个数大于等于3的连通块。

#include <bits/stdc++.h>

using namespace std;

using i32 = int32_t;
using i64 = long long;

#define int i64

using vi = vector<int>;
using pii = pair<int, int>;

const vi dx = {0, 0, 1, -1}, dy = {1, -1, 0, 0};

int n, m, res = 0;

void dfs(vector<vi> g) {
    int ans = n * m;
    vector<vi> col;
    vi cnt;
    cnt.push_back(-1);
    for (auto it: g)
        ans -= it.size(), col.emplace_back(it.size(), 0);
    res = max(res, ans);
    for (int i = 0, t = 0; i < m; i++) {
        for (int j = 0; j < g[i].size(); j++) {
            if (col[i][j]) continue;
            t++, cnt.push_back(0);
            queue<pii> q;
            q.emplace(i, j);
            for (int x, y; not q.empty();) {
                auto _ = q.front();
                x = _.first, y = _.second, q.pop();
                if (col[x][y]) continue;
                col[x][y] = t, cnt[t]++;
                for (int l = 0, fx, fy; l < 4; l++) {
                    fx = x + dx[l], fy = y + dy[l];
                    if (fx < 0 or fx >= m) continue;
                    if (fy < 0 or fy >= g[fx].size()) continue;
                    if (col[fx][fy] or g[fx][fy] != g[x][y]) continue;
                    q.emplace(fx, fy);
                }
            }
        }
    }
    for (int l = 1; l < cnt.size(); l++) {
        if (cnt[l] < 3) continue;
        vector<vi> ng(m);
        for (int j = 0; j < m; j++) {
            for (int i = 0; i < col[j].size(); i++) {
                if (col[j][i] == l) continue;
                ng[j].push_back(g[j][i]);
            }
        }
        dfs(ng);
    }
}

i32 main() {
    ios::sync_with_stdio(false), cin.tie(nullptr);
    cin >> n >> m;
    vector<vi> g(m, vi(n));
    for (int i = 1, x; i <= n; i++)
        for (int j = 0; j < m; j++)
            cin >> g[j][n - i];
    dfs(g);
    cout << res << "\n";
    return 0;
}


E 等式

队友代码

#include<bits/stdc++.h>
using namespace std;
#define int long long
typedef pair<int, int> P;
typedef long long ll;

vector<int> minp(20000001), primes;
int m = 2e7;
void init(vector<int> & minp, vector<int> & primes, int m) {
    for(int i = 2; i <= m; i++) {
        if(!minp[i]) {
            minp[i] = i;
            primes.emplace_back(i);
        }
        for(auto & p : primes) {
            int n = i * p;
            if(n > m) break;
            minp[n] = p;
            if(minp[i] == p) {
                break;
            }
        }
    }
}

void solve () {
    int n;
    cin >> n;
    ll ans = 0;
    for(auto & p : primes) {
        if(p >= n) break;
        int now = n - p;
        if(minp[now] == now) continue;
        unordered_map<int, int> mp;
        while(now > 1) {
            mp[minp[now]] ++ ;
            now /= minp[now];
        }
        int sum = 1;
        for(auto & [x, y] : mp) {
            sum *= (y + 1);
        }
        ans += sum;
    }
    cout << ans << endl;
}


signed main () {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    init(minp, primes, m);
    solve ();
    return 0;
}

F 放大灯

G 航海

首先我们储存的时候可以直接存\(c_i=c_i-a_i\)表示盈利。

\(dfs(x,m,w,ans)\)表示移动到\(x\),剩余本金\(m\),剩余载重\(w\),当前最大盈利\(ans\)

然后我们只要枚举子节点,枚举选不选即可。

直接暴搜,还是不太行的,要维护\(f[x][m][w]\)做一个最优性剪枝和记忆法。

​ 这样搜索已经算很接近了,再加一个\(c_i<=0\)时一定不选即可。

#include <bits/stdc++.h>

using namespace std;

using i32 = int32_t;
using i64 = long long;

//#define int i64

using vi = vector<int>;
using pii = pair<int, int>;

const vi dx = {0, 0, 1, -1}, dy = {1, -1, 0, 0};
const int inf = 1e9;

vi a, b, c, vis;
vector<vi> e;
vector<vector<vi>> f;
int n, res = 0;

void dfs(int x, int m, int w, int ans) {
    if (f[x][m][w] >= ans) return;
    f[x][m][w] = ans, res = max(res, ans);
    if (x == n) return;

    if (vis[x] == 0 and m >= a[x] and w >= b[x] and c[x] > 0) { // 可以购买
        vis[x] = 1;
        for (auto y: e[x])
            dfs(y, m - a[x], w - b[x], ans + c[x]);
        vis[x] = 0;
    }

    for (auto y: e[x]) // 不买
        dfs(y, m, w, ans);

    return;
}


i32 main() {
    ios::sync_with_stdio(false), cin.tie(nullptr);
    int m, v, x;
    cin >> n >> m >> v >> x;
    a.resize(n), b.resize(n), c.resize(n);
    vis.resize(n);
    e.resize(n);
    f = vector<vector<vi>>(n + 1, vector<vi>(m + 1, vi(v + 1, -inf)));
    for (int i = 1, t; i < n; i++) {
        cin >> a[i] >> b[i] >> c[i] >> t;
        c[i] -= a[i], e[i].resize(t);
        for (auto &j: e[i]) cin >> j;
    }
    dfs(x, m, v, 0);
    cout << res << "\n";
    return 0;
}


H 火山喷发

思路就是进行bfs,在过程种判断有没有接触到大海,以及所有接触到的墙壁。

当队列为空时,判断有没有接触到大海,如果接触到就结束,如果没有就把墙壁重新入队,再进行搜索就好。

队友代码

#include<bits/stdc++.h>
using namespace std;
#define int long long
//#define int __int128
#define double long double
typedef pair<int,int>PII;
typedef pair<string,int>PSI;
typedef pair<string,string>PSS;
const int N=100+5,INF=0x3f3f3f3f,Mod=1e9+7,mod=998244353;
const int MAXN=1e8+5;
const double eps=1e-12;
const int dx[4]={-1,1,0,0};
const int dy[4]={0,0,-1,1};



void solve() {
    int n,m,k,now;
    cin>>n>>m>>k;
    now=n*m;
    vector<vector<int>>g(n+5,vector<int>(m+5));
    vector<vector<int>>st(n+5,vector<int>(m+5));
    while(k--){
        int x1,y1,x2,y2;
        cin>>x1>>y1>>x2>>y2;
        if(x1>x2)swap(x1,x2);
        if(y1>y2)swap(y1,y2);
        for(int i=x1;i<=x2;++i)
            for(int j=y1;j<=y2;++j){
                if(!g[i][j])now--;
                g[i][j]=1;
            }
    }
    //207
//    cout<<now<<'\n';
    int sx,sy;
    cin>>sx>>sy;
    queue<PII>q,wal;
    q.push({sx,sy});
    st[sx][sy]=1;
    bool ok=true;
    while(1){
        while(q.size()){
            auto t=q.front();q.pop();
            if(g[t.first][t.second]!=1)now--;
            for(int i=0;i<4;++i){
                int x=t.first+dx[i],y=t.second+dy[i];
                if(x<1||x>n||y<1||y>m) {
                    ok = false;
                }else{
                    if(!st[x][y]){
                        if(g[x][y]==1)wal.push({x,y});
                        else q.push({x,y});
                        st[x][y]=1;
                    }
                }
            }
        }
//        cout<<now<<'\n';
        if(ok&&now>0){
            while(wal.size()){
                auto t=wal.front();wal.pop();
                int x=t.first,y=t.second;
//                g[x][y]=0;
                q.push({x,y});
                st[x][y]=1;
            }
        }else break;
    }
    cout<<now;
}

signed main(){
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    int t=1;
//    cin>>t;
    while(t--){
        solve();
    }
    return 0;
}

I 餐馆

J 统计好数

posted @ 2024-02-03 01:04  PHarr  阅读(525)  评论(0编辑  收藏  举报