2020 年 “联想杯”全国高校程序设计在线邀请赛暨第三届上海理工大学程序设计竞赛 部分题解

题面PDF
(当然这个直接进比赛也能看得到)←比赛链接

A. Archmage

题意:每次sum+y,sum大于x可以-x,sum+y大于n时等于n,问在m次后一共可以减几次x。

虽然是比较水的一道题,但是仍然做了快一个小时…甚至写暴力算法之后用随机数找错误这种事情都干上了,结果最后发现ac代码跟wa了好几遍的代码就差了一个判断,直接裂开了。

这道题由于他有一个x+y<=n,直接简单了不少(虽然搞了快一个小时才发现这个),因为x+y<=n,所以不会出现题目给的sum+y>n的情况,也就是说在x>y的时候,加了m次y,而y不会损失,那么总共可以用的mana数量就是n+(m-1)*y(这里不用m而用m-1是因为顺序是先减x后加y,最后一次加y后不会减x了),这时问题就转化为了总量为n+(m-1)*y,在m次内,最多可以减去多少次x。那么这个时候只需要算n+(m-1)*y中包含多少个x就好了,也就是(n+(m-1)*y)/x。当然还需要做一次判断,判断这个值是否大于m,大于m则输出m就好了。

#include <iostream>
#include <cstring>
#include <cstdio>
#include <string>
#include <algorithm>
#include <cmath>
#include <stack>
#include <queue>
#include <vector>
#include <map>
using namespace std;

int main(){
    //ios::sync_with_stdio(false);
    long long n,x,y,z,m,t,ans = 0;
    cin>>t;
    while(t--){
        scanf("%lld %lld %lld %lld",&n,&m,&x,&y);
        if(x>y&&((m-1)*y+n)/x<=m){
            printf("%lld\n",((m-1)*y+n)/x);
        }
        else{
            printf("%lld\n",m);
        }
    }
    return 0;
}

B. Bamboo Leaf Rhapsody

签到题,算最小距离

#include <iostream>
#include <cstring>
#include <cstdio>
#include <string>
#include <algorithm>
#include <cmath>
#include <stack>
#include <queue>
#include <vector>
#include <map>
using namespace std;

int main(){
    //ios::sync_with_stdio(false);
    int n,x,y,z;
    double ans = 99999999;
    cin>>n;
    for(int i= 0;i<n;i++){
        cin>>x>>y>>z;
        ans = min(ans,sqrt(x*x+y*y+z*z));
    }
    printf("%.3f",ans);
    return 0;
}

C. Cheat Sheet

题意:求在限定字符数量下最多可以有几个不同的字符串。

贪心,首先将重复的去除,然后按照剩余字符串长度从大到小删除,直到剩余字符串长度和小于题目要求,注意空格数量。

#include <iostream>
#include <cstring>
#include <cstdio>
#include <string>
#include <algorithm>
#include <cmath>
#include <stack>
#include <queue>
#include <vector>
#include <map>

using namespace std;
priority_queue<ll> a;
int main() {
    ios::sync_with_stdio(false);
    ll n, x, y, z, m, t, ans = 0,total = 0;
    cin>>n>>m;
    map<string, bool> q;
    string s;
    for(int i = 0;i<m;i++) {
        cin >> s;
        if (!q[s]) {
            ans++;
            q[s] = true;
            total += s.size();
            a.push(s.size());
        }
    }
    total+=ans-1;
    while(total>n){
        total-=a.top();
        total--;
        a.pop();
        ans--;
    }
    cout<<ans<<'\n';
    return 0;
}

D. Disaster Recovery

题意:一个无向图,给出任意边,边权为两顶点对应斐波那契数列上的数之和,求该图最小生成树,并找到最小生成树下最大顶点出度。

其实就是结构体排序+最小生成树的kruskal算法,因为题目数据范围是105,所以不能直接把斐波那契数列算出并求边权。在比较两边权时,可以通过比较两条边终点大小(由于是无向图,这里定义两顶点中较大者为终点,另一点为起点),较大的那一条边边权一定较大,终点相同的时候起点较大的边边权较大,这样就可以讲边排序,进一步应用kruskal最小生成树算法,求出最大顶点出度。

#include <iostream>
#include <cstring>
#include <cstdio>
#include <string>
#include <algorithm>
#include <cmath>
#include <stack>
#include <queue>
#include <vector>
#include <map>

using namespace std;
typedef long long ll;
struct node{
    int u,v;
};
vector<node> a;
long long f[100005];
long long p[100005];
bool cmp(node x,node y){
    if(x.v!=y.v){
        return x.v<y.v;
    }else{
        return x.u<y.u;
    }
}
void init(long long n){
    for(int i = 1;i<=n;i++){
        f[i] = i;
    }
}
int getf(int v){
    if(f[v]==v){
        return v;
    }else{
        f[v] = getf(f[v]);
        return f[v];
    }
}
int merge(int v,int u){
    int t1 = getf(v),t2 = getf(u);
    if(t1!=t2){
        f[t2] = t1;
        return 1;
    }
    return 0;
}
int main(){
    ios::sync_with_stdio(false);
    long long n,x,y,z,m,t,k,ans = 0,count = 0;
    cin>>n>>m;
    init(n);
    for(int i = 0;i<m;i++){
        cin>>x>>y;
        node t;
        if(y<x){
            t.u = y;
            t.v = x;
        }else{
            t.u = x;
            t.v = y;
        }
        a.push_back(t);
    }
    sort(a.begin(),a.end(),cmp);
    for(int i = 0;i<m;i++){
        if(merge(a[i].u,a[i].v)){
            count++;
            p[a[i].u]++;
            p[a[i].v]++;
            ans = max(ans,p[a[i].u]);
            ans = max(ans,p[a[i].v]);
        }
        if(count == n-1){
            break;
        }
    }
    cout<<ans;
    return 0;
}

H. Hay Mower

题意:给出一个n*m矩阵,代表该点每一时间草的生长量,给出k条割草指令,问一共割了多少草。
首先,在这里插入图片描述
其次这道题其实就是对较大数处理稍微有点难度,其他的基本是程设一难度,直接看代码吧。

#include <iostream>
#include <cstring>
#include <cstdio>
#include <string>
#include <algorithm>
#include <cmath>
#include <stack>
#include <queue>
#include <vector>
#include <map>

using namespace std;
typedef long long ll;
long long a[505][505];
long long book[505][505];
int main(){
    ios::sync_with_stdio(false);
    long long n,x,y,z,m,t,k,ans = 0;
    cin>>n>>m>>k;
    memset(book,0,sizeof(book));
    char s;
    for(int i = 1;i<=n;i++){
        for(int j = 1;j<=m;j++){
            cin>>a[i][j];
            a[i][j]%=998244353;
        }
    }
    while(k--){
        cin>>s>>x>>t;
        //t%=998244353;
        if(s=='r'){
            for(int i = 1;i<=m;i++){
                ans+=(t-book[x][i])%998244353*a[x][i]%998244353;
                book[x][i] = t;
            }
        }else if(s=='c'){
            for(int i = 1;i<=n;i++){
                ans+=(t-book[i][x])%998244353*a[i][x]%998244353;
                book[i][x] = t;
            }
        }
        ans%=998244353;
    }
    cout<<ans;
    return 0;
}

这里有一些取余应该没有那么必要,但总之这样是a掉了(逃

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值