北华大学计算机程序设计算法提高训练营个人赛(无L)

题面相当有意思了,题目感觉出的也挺好,L防ak题吧这也太难了

A-洛姐打题日记

AC代码

#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<math.h>
#include<set>
#include<numeric>
#include<string>
#include<string.h>
#include<iterator>
#include<map>
#include<unordered_map>
#include<stack>
#include<list>
#include<queue>
#include<iomanip>

#define endl '\n'
#define int ll
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll>PII;
const int N = 2e5 + 50, MOD = 1e9 + 7;

signed main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    string s;
    cin>>s;
    if(s=="AC")cout<<"Accepted";
    else if(s=="WA")cout<<"Wrong Answer";
    else if(s=="RE")cout<<"Runtime Error";
    else if(s=="TLE")cout<<"Time Limit Exceeded";
    else if(s=="PE")cout<<"Presentation Error";
    else if(s=="MLE")cout<<"Memory Limit Exceeded";
    else cout<<"Compile Error";
    return 0;
}

B-鸡兔同笼

问题解析

设有a个鸡,b个兔子。方程就是a+b=H和a*x+b *y=F。解方程即可。

AC代码

#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<math.h>
#include<set>
#include<numeric>
#include<string>
#include<string.h>
#include<iterator>
#include<map>
#include<unordered_map>
#include<stack>
#include<list>
#include<queue>
#include<iomanip>

#define endl '\n'
#define int ll
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll>PII;
const int N = 2e5 + 50, MOD = 1e9 + 7;

void solve()
{
    int x,y,h,f;
    cin>>x>>y>>h>>f;
    int b=(h*x-f)/(x-y);
    int a=h-b;
    cout<<a<<" "<<b<<endl;
}

signed main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    int t;
    cin>>t;
    while(t--)
        solve();
    return 0;
}

C-小杜的签到

问题解析

把数组升序排序后得到的就是最大值,乘上-1(或把数组降序排序后再算一遍)得到的就是最小值。

AC代码

#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<math.h>
#include<set>
#include<numeric>
#include<string>
#include<string.h>
#include<iterator>
#include<map>
#include<unordered_map>
#include<stack>
#include<list>
#include<queue>
#include<iomanip>

#define endl '\n'
#define int ll
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll>PII;
const int N = 2e5 + 50, MOD = 1e9 + 7;

signed main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    int n;
    cin>>n;
    vector<int>v(n);
    for(int i=0;i<n;i++)cin>>v[i];
    sort(v.begin(),v.end());
    int sum=0;
    for(int i=1;i<n;i++)
    {
        sum+=v[i]-v[i-1];
    }
    cout<<-1*sum<<" "<<sum<<endl;
    return 0;
}

D-我超!原!

问题解析

一开始还想着完全背包,一看复杂度就肯定不是。

直接贪心模拟,先等差数列前n项和算出需要多少经验才能升到x级,但是要注意初始是1级,所以我们算的是前x-1项和。再算一下我们全部资源有多少经验,如果全部资源都用上经验也不够就输出QAQ。

直接贪心,能用20000的就用,用完了或用了会超就用5000,再是1000,最后离升满级就差不到1000经验,我们再看1000的有没有,没有用5000,再没有用20000。

但是有一点,比如所需经验是17000,5000的有4个,1000的有1个,如果我们用了三个5000后用一个1000的,这样还剩1000经验才到目标,此时1000的用完了,我们只能用5000的,超出经验4000,但我们要是一开始就用4个5000的,那超出经验3000。所以我们在算的过程中可以多加一个步骤,我们不继续细分而是直接用当前档次升满级看需要多少经验。最后这两种途径的取最小值即可。

AC代码

#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<math.h>
#include<set>
#include<numeric>
#include<string>
#include<string.h>
#include<iterator>
#include<map>
#include<unordered_map>
#include<stack>
#include<list>
#include<queue>
#include<iomanip>

#define endl '\n'
#define int ll
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll>PII;
const int N = 2e5 + 50, MOD = 1e9 + 7;

signed main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    ll n, m, a, b, c;
    cin >> n >> m >> a >> b >> c;
    ll res = 1000 * (n-1) + ((n-2) * (n - 1)) / 2 * m;
    ll ans = a * 20000 + b * 5000 + c * 1000;
    if (res > ans)
    {
        cout << "QAQ" << endl;
        return 0;
    }
    ans=1e18;
    if (a * 20000 >= res)
    {
        a -= res / 20000;
        res %= 20000;
        if(a>0)ans=min(ans,20000-res);
    }
    else
    {
        res -= a * 20000;
        a = 0;
    }

    if (b * 5000 >= res)
    {
        b -= res / 5000;
        res %= 5000;
        if(b>0)ans=min(ans,5000-res);
    }
    else
    {
        res -= b * 5000;
        b = 0;
    }

    if (c * 1000 >= res)
    {
        c -= res / 1000;
        res %= 1000;
        if(c>0)ans=min(ans,1000-res);
    }
    else
    {
        res -= c * 1000;
        c = 0;
    }
    if (res == 0)cout << res << endl;
    else if (c != 0)cout << min(ans,1000 - res) << endl;
    else if (b != 0)cout << min(ans,5000 - res) << endl;
    else if (a != 0)cout << min(ans,20000 - res) << endl;
    return 0;
}

E-佳乐的迷宫

问题解析

可以先把入口的位置都记录下来,然后我们以出口位置进行bfs(dfs),看那些位置是出口能走到的,那么对应的,这个位置就是能走到出口的,我们再去判断之前那些出口位置有哪些是出口能走到的即可。

AC代码

#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<math.h>
#include<set>
#include<numeric>
#include<string>
#include<string.h>
#include<iterator>
#include<map>
#include<unordered_map>
#include<stack>
#include<list>
#include<queue>
#include<iomanip>

#define endl '\n'
#define int ll
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll>PII;
const int N = 2e5 + 50, MOD = 1e9 + 7;

int st[1050][1050];
int dx[] = { 1,0,-1,0 }, dy[] = { 0,1,0,-1 };
signed main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    int n, m, k;
    cin >> n >> m >> k;
    vector<string>v(n);
    for (int i = 0; i < n; i++)cin >> v[i];
    vector<PII>ans(k);
    for (int i = 0; i < k; i++)cin >> ans[i].first >> ans[i].second;
    int x, y;
    cin >> x >> y;
    queue<PII>que;
    que.push({ x,y });
    st[x][y] = 1;
    while (!que.empty())
    {
        int len = que.size();
        for (int i = 0; i < len; i++)
        {
            auto t = que.front();
            que.pop();
            for (int j = 0; j < 4; j++)
            {
                int a = t.first + dx[j], b = t.second + dy[j];
                if (a  >= 1 && b  >= 1 && a  <= n && b  <= m &&v[a-1][b-1] == '.' && st[a ][b] == 0)
                {
                    st[a ][b] = 1;
                    que.push({ a,b });
                }
            }
        }
    }
    vector<int>res;
    int cnt = 0;
    for (auto i : ans)
    {
        cnt++;
        if (st[i.first][i.second])
        {
            res.push_back(cnt);
        }
    }
    cout << res.size() << endl;
    for (auto i : res)cout << i << " ";
    return 0;
}

F-三四五

问题解析

升级办nim游戏,这里先说一个nim游戏的必胜秘诀,如果你每次能拿最多x个石头,那么只要总石头数不是(x+1)的倍数,你就可以赢,如果是则必输。

所以只要第一堆石头是4的倍数or第二堆是5的倍数or第三堆是6的倍数,那么这堆石头我们肯定会输。但这题不是单纯的看是否必输or必赢,而是看谁先输,比如石头数是1,100,20,虽然第二堆石头是5的倍数,我们必输,但是第一堆石头只有1个,我们拿完后对面就直接输了,第一堆石头可以在第一轮分出胜负,而第二堆要20轮才能分出胜负,显然是我们赢。所以我们要看,输最快会在第几轮输,赢最快会在第几轮赢,谁小,那就说明我们会赢(输)。

AC代码

#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<math.h>
#include<set>
#include<numeric>
#include<string>
#include<string.h>
#include<iterator>
#include<map>
#include<unordered_map>
#include<stack>
#include<list>
#include<queue>
#include<iomanip>

#define endl '\n'
#define int ll
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll>PII;
const int N = 2e5 + 50, MOD = 1e9 + 7;

void solve()
{
    int a,b,c;
    cin>>a>>b>>c;
    bool flag=true;
    int winer=1e9,loser=1e9;
    if(a%4==0)loser=min(loser,a/4);
    else winer=min(winer,a/4);
    
    if(b%5==0)loser=min(loser,b/5);
    else winer=min(winer,b/5);
    
    if(c%6==0)loser=min(loser,c/6);
    else winer=min(winer,c/6);
    
    if(winer<loser)cout<<"(^-^)"<<endl;
    else cout<<"(T-T)"<<endl;
}

signed main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    int t;
    cin>>t;
    while(t--)
        solve();
    return 0;
}

G-杰哥的疑问

问题解析

可以用哈希表记录一下每个数的出现次数,然后对于一个数x来说,能和他相加后等于m的数肯定是m-x。那我们只要看m-x这个数出现了多少次,且x又出现了多少次,就可以知道x和m-x一共可以组合出多少个满足条件的数对。

AC代码

#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<math.h>
#include<set>
#include<numeric>
#include<string>
#include<string.h>
#include<iterator>
#include<map>
#include<unordered_map>
#include<stack>
#include<list>
#include<queue>
#include<iomanip>

#define endl '\n'
#define int ll
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll>PII;
const int N = 2e5 + 50, MOD = 1e9 + 7;

signed main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    int n,m,x,cnt=0;
    cin>>n>>m;
    unordered_map<int,int>mymap;
    for(int i=0;i<n;i++)
    {
        cin>>x;
        cnt+=mymap[m-x];
        mymap[x]++;
    }
    cout<<cnt;
    return 0;
}

H-墨染的斯汀木

问题解析

为了方便,我们可以先把没被污染的字符串全部变成小写字母的形式,然后我们再根据第一个字符串中大小写的情况来还原字符串即可。

AC代码

#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<math.h>
#include<set>
#include<numeric>
#include<string>
#include<string.h>
#include<iterator>
#include<map>
#include<unordered_map>
#include<stack>
#include<list>
#include<queue>
#include<iomanip>

#define endl '\n'
#define int ll
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll>PII;
const int N = 2e5 + 50, MOD = 1e9 + 7;

signed main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    string a,b,s,c;
    cin>>a>>b;
    int n=a.size(),m;
    for(auto i:b)
    {
        if(i>='a'&&i<='z')c+=i;
        else 
        {
            c+=(i+32);
            c+=(i+32);
        }
    }
    m=c.size();
    int l=0,r=0;
    while(l<n&&r<m)
    {
        if(a[l]=='?'||(a[l]>='a'&&a[l]<='z'))s+=c[r++];
        else 
        {
            s+=(c[r]-32);
            r+=2;
        }
        l++;
    }
    cout<<s<<endl;
    return 0;
}

I-Darling(Easy.)J-Darling(Hard.)

问题解析

i题数据类型教少,建图之后对于每次询问我们都跑一便bfs来求最近的异性即可。

每次向和自己链接的其它点看去,如果这个点和我们的性别不同,那根据bfs特性,这个就是我们最近的异性,如果周围没有异性,那我们就把和自己相邻的点再送去下一轮bfs,同时步数+1。

AC代码

#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<math.h>
#include<set>
#include<numeric>
#include<string>
#include<string.h>
#include<iterator>
#include<map>
#include<unordered_map>
#include<stack>
#include<list>
#include<queue>
#include<iomanip>

#define endl '\n'
#define int ll
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll>PII;
const int N = 2e5 + 50, MOD = 1e9 + 7;

unordered_map<int,vector<int>>mymap;
signed main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    int n,m,t,x,y;
    cin>>n>>m>>t;
    vector<int>sex(n+1);
    for(int i=1;i<=n;i++)cin>>sex[i];
    for(int i=0;i<m;i++)
    {
        cin>>x>>y;
        mymap[x].push_back(y);
        mymap[y].push_back(x);
    }
    while(t--)
    {
        int res=0;
        cin>>x;
        queue<int>que;
        que.push(x);
        y=-1;
        vector<int>st(1001);
        while(!que.empty())
        {
            res++;
            int len=que.size();
            for(int i=0;i<len;i++)
            {
                int tt = que.front();
                que.pop();
                for(auto j:mymap[tt])
                {
                    if(st[j]==0)
                    {
                        if(sex[j]!=sex[x])
                        {
                        	//找到了,我们直接结束bfs
                            y=res;
                            break;
                        }
                        else 
                        {
                            que.push(j);
                            st[j]=1;
                        }
                    }
                }
                if(y!=-1)break;
            }
            if(y!=-1)break;
        }
        cout<<y<<endl;
    }
    return 0;
}

至于j题,数据提到了1e6,这样再用上面的方法肯定会t。但还是可以用bfs来写。

我们可以把问题分成两部分:给性别为0的找最近的1,给性别为1的找最近的0。用一个二维数组f来存结果:f[i] [0]表示i到最近的0的距离,f[i] [1]表示i到最近的1的距离。

求哪个性别,就可以先遍历全部的点,把那个性别的点存入队列里,并且把f[i] [当前性别]设为0,因为里它最近的这个性别就是他自己。再进行bfs,我们只bfs到哪些性别和我们不同的点上,如果j是和i相连且性别不同的点,那么就有:

f[j] [当前性别]=f[i] [当前性别]+1;(注意当前性别不是说j的性别,而是我们现在求的性别)

这样在k次询问时,我们可以先判断询问的点是哪个性别,再去对应的数组找结果。

AC代码

#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<math.h>
#include<set>
#include<numeric>
#include<string>
#include<string.h>
#include<iterator>
#include<map>
#include<unordered_map>
#include<stack>
#include<list>
#include<queue>
#include<iomanip>

#define endl '\n'
#define int ll
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll>PII;
const int N = 1e6 + 50, MOD = 1e9 + 7;
unordered_map<int, vector<int>>mymap;
int f[N][2], sex[N];
int n, m, t, x, y;

void bfs(int x)
{
    queue<int>que;
    for(int i=1;i<=n;i++)
        if (sex[i] == x)
        {
            que.push(i);
            f[i][x] = 0;
        }
    while (!que.empty())
    {
        int ans = que.front();
        que.pop();
        for (auto i : mymap[ans])
        {
            if (f[i][x] == -1 && sex[i] != x)
            {
                f[i][x] = f[ans][x] + 1;
                que.push(i);
            }
        }
    }
}

signed main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    cin >> n >> m >> t;
    for (int i = 1; i <= n; i++)cin >> sex[i];
    for (int i = 0; i < m; i++)
    {
        cin >> x >> y;
        mymap[x].push_back(y);
        mymap[y].push_back(x);
    }
    memset(f, -1, sizeof f);
    bfs(0);
    bfs(1);
    while (t--)
    {
        cin >> x;
        if (sex[x])
        {
            cout << f[x][0] << endl;
        }
        else cout << f[x][1] << endl;
    }
    
    return 0;
}

K-小杜返校记

问题解析

按照舱位和时间找对应的手续费率pi,计算式:*n=n(1-pi/100)**。

AC代码

#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<math.h>
#include<set>
#include<numeric>
#include<string>
#include<string.h>
#include<iterator>
#include<map>
#include<unordered_map>
#include<stack>
#include<list>
#include<queue>
#include<iomanip>

#define endl '\n'
#define int ll
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll>PII;
const int N = 2e5 + 50, MOD = 1e9 + 7;

signed main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    vector<vector<double>>v(3,vector<double>(3));
    double money;
    int h=0;
    cin>>money>>h;
    string s,fw;
    cin>>s>>fw;
    for(int i=0;i<3;i++)
        for(int j=0;j<3;j++)
            cin>>v[i][j];
    int x;
    if(s[0]=='F')x=0;
    else if(s[0]=='B')x=1;
    else x=2;
    
    if(h>=336)money=money;
    else if(h>=48)money=money*(1-v[x][0]/100);
    else if(h>=4)money=money*(1-v[x][1]/100);
    else money=money*(1-v[x][2]/100);
    cout << fixed << setprecision(2) << money << endl;
    return 0;
}