【CF】Day94——2025郑州CCPC(DJFHMGE)

Problem D. 2025

题目:

思路:

签到

模拟即可 ,不多解释

代码:

#include <iostream>
#include <algorithm>
#include<cstring>
#include<cctype>
#include<string>
#include <set>
#include <vector>
#include <cmath>
#include <queue>
#include <unordered_set>
#include <map>
#include <unordered_map>
#include <stack>
#include <memory>
using namespace std;
#define int long long
#define yes cout << "Yes\n"
#define no cout << "No\n"
bool check(int x)
{
    int q = sqrt(x);
    if (q * q != x)
    {
        return false;
    }
    return true;
}
void solve()
{
    int y;
    cin >> y;
    if (!check(y))
    {
        no;
        return;
    }
    int x = 0;
    while (y)
    {
        x += y % 10;
        y /= 10;
    }
    if (!check(x))
    {
        no;
        return;
    }  
    yes;
}

signed main()
{
    cin.tie(0)->sync_with_stdio(false);
    int t = 1;
    while (t--)
    {
        solve();
    }
    return 0;
}

Problem J. Ring Trick

题目:

思路:

签到

模拟即可

代码:

#include <iostream>
#include <algorithm>
#include<cstring>
#include<cctype>
#include<string>
#include <set>
#include <vector>
#include <cmath>
#include <queue>
#include <unordered_set>
#include <map>
#include <unordered_map>
#include <stack>
#include <memory>
using namespace std;
#define int long long
#define yes cout << "Yes\n"
#define no cout << "No\n"
int holes_cnt[26] = { 1, 2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 };
void solve()
{
    string s;
    cin >> s;
    int ans = 0;
    for (int k = 0; k < 26; k++)
    {
        int temp = 0;
        for (int i = 0; i < s.size(); i++)
        {
            temp += holes_cnt[(s[i] - 'A' + k) % 26];
        }
        ans = max(ans, temp);
    }
    cout << ans << endl;
}

signed main()
{
    cin.tie(0)->sync_with_stdio(false);
    int t = 1;
    while (t--)
    {
        solve();
    }
    return 0;
}

Problem F. 幻形之路

题目:

思路:

BFS + 思维

题目说我们可以开一次桂使得我们可以连续穿墙 k 步,求最小 k

这里注意是连续穿墙 k 步,而不是有 k 步能穿墙,所以我们不能简单的BFS

我们这里可以采用一个双向BFS的想法,我们分别从起点和终点出发,看看什么时候哪些点会碰到墙,这里BFS两遍即可,同时储存这些下一步就要碰墙的点

然后如果不能直接到,那么就要穿墙,此时我们直接从两个集合中暴力枚举即可,最后取一个最小距离即可(不过居然没超时,我们应该是要将两个集合再进行一次BFS,此时以前者为源点集合,后者为终点集合)

代码:

#include <iostream>
#include <algorithm>
#include<cstring>
#include<cctype>
#include<string>
#include <set>
#include <vector>
#include <cmath>
#include <queue>
#include <unordered_set>
#include <map>
#include <unordered_map>
#include <stack>
#include <memory>
using namespace std;
#define int long long
#define yes cout << "Yes\n"
#define no cout << "No\n"
pair<int, int> dir[4] = { {1,0},{-1,0},{0,-1},{0,1} };
void solve()
{
    int n, m;
    cin >> n >> m;
    vector<vector<char>> mp(n + 1, vector<char>(m + 1, 0));
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= m; j++)
        {
            cin >> mp[i][j];
        }
    }
    vector<vector<int>> vis(n + 1, vector<int>(m + 1, 0));
    queue<pair<int, int>> q,q2;
    q.push({ 1,1});
    q2.push({ m,n });
    set<pair<int, int>> fromS, fromE;
    while (!q.empty())
    {
        auto t = q.front();
        q.pop();
        int x = t.first;
        int y = t.second;
        if (x == m && y == n)
        {
            cout << "0\n";
            return;
        }
        if (vis[y][x])
        {
            continue;
        }
        vis[y][x] = 1;
        for (int i = 0; i < 4; i++)
        {
            int newx = x + dir[i].second;
            int newy = y + dir[i].first;
            if (newx < 1 || newy < 1 || newx > m || newy > n)
            {
                continue;
            }
            if (mp[newy][newx] == '#')
            {
                fromS.insert({ y,x });
                continue;
            }
            q.push({newx,newy});
        }
    }
    while (!q2.empty())
    {
        auto t = q2.front();
        q2.pop();
        int x = t.first;
        int y = t.second;
        if (vis[y][x])
        {
            continue;
        }
        vis[y][x] = 1;
        for (int i = 0; i < 4; i++)
        {
            int newx = x + dir[i].second;
            int newy = y + dir[i].first;
            if (newx < 1 || newy < 1 || newx > m || newy > n)
            {
                continue;
            }
            if (mp[newy][newx] == '#')
            {
                fromE.insert({ y,x });
                continue;
            }
            q2.push({ newx,newy });
        }
    }
    int ans = 1e9;
    for (auto& p1:fromS)
    {
        for (auto & p2 : fromE)
        {
            ans = min(ans, abs(p1.first - p2.first) + abs(p1.second - p2.second) - 1);
        }
    }
    cout << ans << endl;
}

signed main()
{
    cin.tie(0)->sync_with_stdio(false);
    int t = 1;
    cin >> t;
    while (t--)
    {
        solve();
    }
    return 0;
}

Problem H. 树论函数

题目:

思路:

观察 or 猜测

这里直接猜测得出来,我们可以计算前几个值,如 1 2,2 3,3 4,发现这几对都能连接到一个节点上,所以猜测相邻的两个节点可以连接到同一个父节点上,即所有节点都能互通

(其实看数据也应该知道要往是否有结论上猜)

代码:

#include <iostream>
#include <algorithm>
#include<cstring>
#include<cctype>
#include<string>
#include <set>
#include <vector>
#include <cmath>
#include <queue>
#include <unordered_set>
#include <map>
#include <unordered_map>
#include <stack>
#include <memory>
using namespace std;
#define int long long
#define yes cout << "Yes\n"
#define no cout << "No\n"

void solve()
{
    int s, l, r;
    cin >> s >> l >> r;
    cout << r - l + 1 << endl;
}

signed main()
{
    cin.tie(0)->sync_with_stdio(false);
    int t = 1;
    cin >> t;
    while (t--)
    {
        solve();
    }
    return 0;
}

Problem M. 川陀航空学院

题目:

思路:

DFS + 思维

题目告诉我们最后要连成一颗树,那么显然一共只需要 n - 1条边,所以我们可以直接暴力遍历所有边,看看那些边是有效的,设其为 cnt(有效即代表这条边连的点之前未走过,因为我们只需要访问一遍即可,多次访问肯定是重复的,即多余的)

那么我们就要删去 m - cnt 条边,同时要增加 n - 1 - cnt 条边,因此答案就是 n-1-cnt + m-cnt

特别的,由于给定的图不一定是联通的,所以我们要遍历所有节点来DFS

代码:

#include <iostream>
#include <algorithm>
#include<cstring>
#include<cctype>
#include<string>
#include <set>
#include <vector>
#include <cmath>
#include <queue>
#include <unordered_set>
#include <map>
#include <unordered_map>
#include <stack>
#include <memory>
using namespace std;
#define int long long
#define yes cout << "Yes\n"
#define no cout << "No\n"
vector<vector<int>> g(1000005);
vector<int> vis(1000006,0);
int cnt = 0;
void dfs(int fa,int se)
{
    vis[se] = 1;
    for (auto & son : g[se])
    {
        if (son == fa || vis[son]) continue;
        dfs(se, son);
        cnt++;
    }
}

void solve()
{
    int n, m;
    cin >> n >> m;
    for (int i = 0; i < m; i++)
    {
        int u, v;
        cin >> u >> v;
        g[u].push_back(v);
        g[v].push_back(u);
    }
    for (int i = 1; i <= n; i++)
    {
        if (!vis[i])
        {
            dfs(i, i);
        }
    }
    int need = n - 1;
    cout << (need - cnt) + (m - cnt) << endl;
}

signed main()
{
    cin.tie(0)->sync_with_stdio(false);
    int t = 1;
    while (t--)
    {
        solve();
    }
    return 0;
}

Problem G. 直径与最大独立集

题目:

思路:

思维 + 构造

结论:只要 n 不为 4 就能构造出来,具体方法如下图

没啥讲的,手画找规律即可 

代码:

#include <iostream>
#include <algorithm>
#include<cstring>
#include<cctype>
#include<string>
#include <set>
#include <vector>
#include <cmath>
#include <queue>
#include <unordered_set>
#include <map>
#include <unordered_map>
#include <stack>
#include <memory>
using namespace std;
#define int long long
#define yes cout << "Yes\n"
#define no cout << "No\n"

void solve()
{
    int n;
    cin >> n;
    if (n == 4)
    {
        cout << "-1\n";
        return;
    }
    if (n == 2)
    {
        cout << "1 2\n";
        return;
    }
    int flag = 0;
    if (n % 2 == 0)
    {
        n--;
        flag = 1;
    }
    int need = (n - 3) / 2;
    for (int i = 1; i < 3 + need; i++)
    {
        cout << i << " " << i + 1 << endl;
    }
    if (flag)
    {
        cout << 3 + need << " " << n+1 << endl;
    }
    int fa = 2, start = 3 + need + 1;
    for (int i = 0; i < need; i++)
    {
        cout << start++ << " " << fa++ << endl;
    }
}

signed main()
{
    cin.tie(0)->sync_with_stdio(false);
    int t = 1;
    cin >> t;
    while (t--)
    {
        solve();
    }
    return 0;
}

Problem E. 双生魔咒

题目:

思路: 

贪心 + 字典树

题解没看懂,但是我会贪(猜)

我们先按照字典序排好,贪心的想,因为按照字典序排序,那么这样就能保证相邻的字符串前缀更多,此时我们按照奇偶顺序来分配 根 和 引 一定是最优的

然后套用字典树加一点小更改即可,先把奇数的放进字段数,然后偶数的进行查询

(复习字典树)

代码:

#include <iostream>
#include <algorithm>
#include<cstring>
#include<cctype>
#include<string>
#include <set>
#include <vector>
#include <cmath>
#include <queue>
#include <unordered_set>
#include <map>
#include <unordered_map>
#include <stack>
#include <memory>
#include <complex>
using namespace std;
#define int long long
#define yes cout << "Yes\n"
#define no cout << "No\n"

int idx = 0;
int cnt[1000000];
int tire[100005][26];
int ans = 0;

void insert(const string& s)
{
    int p = 0;
    for (auto &c : s)
    {
        if (!tire[p][c])
        {
            tire[p][c] = ++idx;
        }
        p = tire[p][c];
        cnt[p]++;
    }
}

void query(const string& s)
{
    int p = 0;
    for (auto& c : s)
    {
        if (!tire[p][c])
        {
            return;
        }
        p = tire[p][c];
        ans += cnt[p];
    }
}


void solve()
{
    int n;
    cin >> n;
    vector<string> s(2 * n);
    for (int i = 0; i < 2*n; i++)
    {
        cin >> s[i];
    }
    sort(s.begin(), s.end());
    for (int i = 0; i < 2*n; i+=2)
    {
        insert(s[i]);
    }
    for (int i = 1; i < 2*n; i+=2)
    {
        query(s[i]);
    }
    cout << ans << endl;
}

signed main()
{
    cin.tie(0)->sync_with_stdio(false);
    int t = 1;
    while (t--)
    {
        solve();
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值