天梯赛2022年

插松枝

这题主要恶心点在于题意属于是很难在赛时看明白,当时浪费了快一个小时,之后仔细捋了一下思路发现也就是stl,需要注意的就是卡格式以及各种情况不要漏。

#include<iostream>
#include<cstring>
#include<algorithm>
#include<stack>
#include<deque>
#include<vector>
using namespace std;
const int N = 1e3 + 10;
deque<int> p;
stack<int> hezi;
vector<int> ans[N];
int n, m, k;
int getb(int temp, int num)
{
    int t = 0;
    if (hezi.size())
    {
        t = hezi.top();
        if (t > num)
        {
            if (!p.size()) return -1;
            else
            {
                while (p.size())
                {
                    auto t = p.front();
                    p.pop_front();
                    if (t <= num)
                    {
                        return t;
                    }
                    else
                    {
                        //cout << t << "tnum " << num << endl;
                        if (hezi.size() == m)
                        {
                            p.push_front(t);
                            return -1;
                        }
                        else hezi.push(t);
                    }
                }
            }
        }
        else
        {
            hezi.pop();
            return t;
        }
    }
    else
    {
        while (p.size())
        {
            auto t = p.front();
            p.pop_front();
            if (t <= num)
            {
                return t;
            }
            else
            {
                //cout << t << "tnum " << num << endl;
                if (hezi.size() == m)
                {
                    p.push_front(t);
                    return -1;
                }
                else hezi.push(t);
            }
        }
        return t;
    }
    return -2;
}
void solve()
{
    cin >> n >> m >> k;
    int temp = 0;
    for (int i = 1; i <= n; i++)
    {
        int num;
        cin >> num;
        p.push_back(num);
    }
    while (p.size()|| hezi.size())
    {
        int t = 0;
        if (ans[temp].size() == 0)
        {
            t = getb(temp, 110);
            if (t == -1)
            {
                temp++;
                continue;
            }
            else if(t==-2) continue;
            ans[temp].push_back(t);
        }
        else if (ans[temp].size() == k)
        {
            temp++;
        }
        else
        {
            int len = ans[temp].size();
            t = getb(temp, ans[temp][len - 1]);
            //cout << "ans" << ans[temp][len - 1] << endl;
            if (t == -1)
            {
                temp++;
                continue;
            }
            else if(t==-2) continue;
            ans[temp].push_back(t);
        }
        //cout << temp << "temp" << t << "t" << hezi.size() << "盒子";
        //for (auto x : ans[temp]) cout << x << " ";
        //puts("");

    }
    for (int i = 0; i < temp; i++)
    {
        for (int j = 0; j < ans[i].size(); j++)
        {
            if (j == ans[i].size() - 1) cout << ans[i][j];
            else cout << ans[i][j] << " ";
        }
        puts("");
    }
    if (ans[temp].size())
    {
        for (int j = 0; j < ans[temp].size(); j++)
        {
            if (j == ans[temp].size() - 1) cout << ans[temp][j];
            else cout << ans[temp][j] << " ";
        }
    }

}
int main()
{
    solve();
}

老板的作息表

算上0点和24点输出首位不连续的时间段就可以

#include <bits/stdc++.h>
using namespace std;
int n;
vector<pair<string,string>> q;
 
 
 
int main(){
    cin >> n;
    while(n -- ){
        string a, b, c;
        cin >> a >> b  >> c;
        q.push_back({a, c});
    }
    q.push_back({"", "00:00:00"});
    q.push_back({"23:59:59", ""});
    sort(q.begin(), q.end());
    
    int m = q.size();
    
    for (int i = 0; i < m - 1; i ++ )
        if (q[i].second != q[i + 1].first)
            cout << q[i].second << " - " << q[i + 1].first << endl;
    return 0;
}

龙龙送外卖

对于每个点从根部开始从下往上搜,记录深度,只要搜到我曾经搜过的点的位置,就可以停止,表示这是一段新路径,最后减去当时可以走的最长路径,也就是其他路径来回走两遍,最长路径只走一遍。

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 1e5 + 10;
int dep[N], fa[N];
int n, m, beg, ans, maxn;
int dfs(int a,int l)
{
    if (a == beg || dep[a] != 0)
    {
        
        return l * 2;
    }
    int p = dfs(fa[a], l + 1);
    dep[a] = dep[fa[a]] + 1;
    return p;
}
void solve()
{
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
    {
        cin >> fa[i];
        if (fa[i] == -1) beg = i;
    }
    while (m--)
    {
        int s;
        cin >> s;
        ans += dfs(s, 0);
        maxn = max(maxn, dep[s]);
        cout << ans - maxn << endl;
    }
    
}
int main()
{
    solve();
}

大众情人

距离感是可以传递的,这题目的是要我们判断所有点的距离感找到之中的大众情人,所以考虑弗洛伊德

o(n3)N<500,可行。查找是还需要考虑性别,男对女和女对男都需要找,因为可以重复,还需要排序,这里用了map。


#include<iostream>
#include<cstring>
#include<vector>
#include<cstring>
#include<map>
using namespace std;
const int N = 520;
int g[N][N], n;
bool sex[N];
map<int, vector<int>> ansboy, ansgirl;
void solve()
{
    cin >> n;
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++)
        {
            if (i == j) g[i][j] = 0;
            else g[i][j] = 0x3f3f3f3f;
        }
    for (int i = 1; i <= n; i++)
    {
        char s;
        int num;
        cin >> s >> num;
        if (s == 'M') sex[i] = 1;
        while (num--)
        {
            int a, b;
            scanf("%d:%d", &a, &b);
            g[i][a] = min(g[i][a], b);
        }
    }
    for (int k = 1; k <= n; k++)
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= n; j++)
            {
                g[i][j] = min(g[i][j], g[i][k] + g[k][j]);
            }
    for (int i = 1; i <= n; i++)
    {
        int res = 0;
        if (sex[i])
        {
            for (int j = 1; j <= n; j++)
            {
                if (i == j || sex[j]) continue;
                res = max(res, g[j][i]);
            }
            ansboy[res].push_back(i);
        }
        else
        {
            for (int j = 1; j <= n; j++)
            {
                if (i == j || sex[j] == 0) continue;
                res = max(res, g[j][i]);
            }
            ansgirl[res].push_back(i);
        }
    }
    for (auto x : ansgirl)
    {
        for (int i = 0; i < x.second.size(); i++)
        {
            if(i== x.second.size()-1) cout << x.second[i];
            else cout << x.second[i] << " ";
        }
        puts("");
        break;
    }
    for (auto x : ansboy)
    {
        for (int i = 0; i < x.second.size(); i++)
        {
            if (i == x.second.size() - 1) cout << x.second[i];
            else cout << x.second[i] << " ";
        }
        puts("");
        break;
    }

}
int main()
{
    solve();
}

千手观音

根据输出的大小关系,建边,通过bfs跑出拓扑序,至于不确定的先后关系则通过优先队列排序再存进答案


#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
typedef long long ll;
map<string,int>mp;
int tot;
string st[10005];
vector<int>to[10005];
int in[10005];
void slove(){
    int n;
    cin>>n;
    vector<string>pre;
    for(int i=1;i<=n;i++){
        string s;
        cin>>s;
        vector<string>now;
        int cnt=0;
        string t="";
        for(int j=0;j<s.length();j++){
            if(s[j]=='.'||j+1==s.length()){
                if(j+1==s.length())t+=s[j];
                if(!mp.count(t))mp[t]=++tot,st[tot]=t;
                now.push_back(t);
                t="";
            }
            else t+=s[j];
        }
        if(i==1)pre=now;
        else{
            if(pre.size()==now.size()){
                for(int i=0;i<pre.size();i++){
                    if(pre[i]==now[i])continue;
                    to[mp[pre[i]]].push_back(mp[now[i]]);
                    in[mp[now[i]]]++;
                    break;
                }
            }
            pre=now;
        }
    }
    priority_queue<string,vector<string>,greater<string> >q;
    for(int i=1;i<=tot;i++){
        if(in[i]==0)q.push(st[i]);
    }
    vector<string>ans;
    while(q.size()){
        string t=q.top();q.pop();
        int x=mp[t];
        ans.push_back(t);
        for(auto y:to[x]){
            in[y]--;
            if(in[y]==0){
                q.push(st[y]);
            }
        }
    }
    bool p=false;
    for(auto x:ans){
        if(p)cout<<".";
        p=true;
        cout<<x;
    }
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    int T=1;
//    cin>>T;
    while(T--){
        slove();
    }
    return 0;
}

关于深度优先搜索和逆序对的题应该不会很难吧这件事

把问题中的点拆分成两种,分别讨论,第一类点是有祖先关系的点对,第二类点是无关系的点对,对于第一类点,他的逆序对对数就是固定的,因为祖先关系是固定的,所以在任意个dfs序中,逆序对个数都是相同的,因此只需要找出祖先关系中有几对逆序对点即可,这一步可以通过树状数组维护,dfs遍历这个点时插入树状数组,作为祖先点,直到递归离开这个点,删去插入的这个点,每次遍历到一个新的点,就求出比这个点大的所有点的个数就是这个点所包含的逆序对个数,最后加起来就时这一部分答案。

第二类点这样的结点对在每种DFS序中的顺序不固定,但是我们经过观察完全可以发现,这样的结点对要不然是逆序对,要不然不是逆序对,概率都是1/2。

所以这一部分答案就是第二类点逆序对个数/2,但是第二类点逆序对个数怎么求呢,我们可以根据点对总数减去第一类点逆序对个数,也就是(n-1)*n/2-第一类点点对个数,第一类点点对个数我们可以根据

对每一个点找以这个点为根节点的子树的逆序对个数,可以发现只找左侧是根节点的点对个数就是子树除去根节点的节点个数,因此dfs过程中维护一下即可

最后需要求的是dfs序,这一部分需要dfs递归,从下往上更新得出,对于i节点,我们可以通过i节点的子节点的排列组合,以及各个子节点的dfs序相乘得到。从下往上更新最后就可以得到根节点开始的dfs序。

详见代码

#include<iostream>
#include<algorithm>
#include<cstring>
#define int long long
using namespace std;
const int N = 3e5 + 10, mod = 1e9 + 7;
int e[N*2], ne[N*2], idx, h[N];
int dp[N], cnt[N], root, a[N], n, deg[N], mx[N], jie[N];
int lowbit(int x)
{
    return x & -x;
}
void init()
{
    memset(h, -1, sizeof h);
    jie[0] = 1;
    for (int i = 1; i <= n; i++)
        jie[i] = jie[i - 1] * i % mod;
}
int qmi(int a, int b, int m)
{
    int res = 1;
    a %= m;
    while(b)
    {
        if (b & 1) res = res * a % m;
        b >>= 1;
        a = a * a % m;
    }
    return res;
}
void adde(int a, int b)
{
    e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
void add(int x, int val)
{
    for (int i = x; i <= n; i+=lowbit(i))
        a[i] += val;
}
int ask(int x)
{
    int res = 0;
    for (int i = x; i; i -= lowbit(i))
        res += a[i],res%=mod;
    return res;
}
void dfs(int r, int fa)
{
    
    mx[r] = ask(n) - ask(r);
    
    //cout << r << " r " << mx[r] << endl;
    dp[r] = 1;
    add(r, 1);
    for (int i = h[r]; ~i; i = ne[i])
    {
        int j = e[i];
        if (j == fa) continue;
        deg[r]++;
        dfs(j, r);
        dp[r] = dp[r] * dp[j] % mod;
        cnt[r] = (cnt[r] + cnt[j]) % mod;
    }
    dp[r] = (dp[r] * jie[deg[r]]) % mod;
    cnt[r] = (cnt[r] + deg[r]) % mod;
    add(r, -1);
}
int cal(int x)
{
    return x * (x - 1) % mod * qmi(2, mod - 2, mod) % mod;
}
void solve()
{
    
    cin >> n >> root;
    init();
    for (int i = 1; i < n; i++)
    {
        int a, b;
        cin >> a >> b;
        adde(a, b), adde(b, a);
    }
    dfs(root, 0);
    int sum = cal(n);
    
    for (int i = 1; i <= n; i++)
        sum -= cnt[i],sum%=mod;
    int res = sum * qmi(2, mod - 2, mod) % mod;
    for (int i = 1; i <= n; i++)
        res = (res + mx[i]) % mod;
    res = res * dp[root] % mod;
    cout << res << endl;
}
signed main()
{
    solve();
}
天梯赛(ACM)是一种面向计算机竞赛的比赛形式,即ACM国际大学生程序设计竞赛。这项比赛旨在促进学生的计算机科学技能和创新思维,并且是计算机专业学生之间最有声望和重要的竞赛之一。 在天梯赛中,参赛队伍需要在规定的时间内解决多个问题,这些问题通常是涉及算法、数据结构、自动机等计算机科学领域的难题。比赛中,每个队伍通常有三名队员组成,他们需要一起分析问题、设计算法,并通过程序编码来解决问题。此外,比赛规定了每个题目的时间和内存限制,参赛队伍需要在这些限制下得出正确的结果。 在天梯赛中,要想在短时间内解决尽可能多的问题,参赛队伍必须具备扎实的计算机科学基础知识,并且具有良好的团队合作和沟通能力。他们需要能够迅速分析问题、抽象问题、设计高效算法,并且通过编程实现。此外,参赛队伍在备赛阶段也需要大量的刷题和训练,以提高解题能力和熟悉常见的问题类型。 天梯赛不仅考察了参赛队伍的计算机科学技术水平,也考察了他们的解决问题的能力、团队协作能力和时间管理能力。此外,天梯赛也为参赛队伍提供了展示和交流的机会,他们可以与其他参赛队伍分享经验、学习他们的解题思路,从中得到启发和提高。 总之,天梯赛是一项注重计算机科学技术和创新能力的竞赛,通过比赛的形式促进学生的学习、交流和提高。它是计算机竞赛中最具代表性和声望的竞赛之一,也是培养优秀计算机科学人才的重要途径之一。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值