2023 山东省大学生程序设计竞赛

在这里插入图片描述

A.订单

按ai排序,看到ai天时货物够不够

code:

#include<bits/stdc++.h>
#define int long long

using namespace std;

const int N = 1e2 + 7;
pair<int,int> p[N];
int n,k;

void solve(){
	cin >> n >> k;
	for(int i = 1;i <= n;i ++) cin >> p[i].first >> p[i].second;
	int sum = 0;
	sort(p + 1,p + n + 1);
	for(int i = 1;i <= n;i ++){
		sum += (p[i].first - p[i - 1].first) * k;
		sum -= p[i].second;
		if(sum < 0){
			cout << "No" << endl;
			return; 
		} 
	} 
	cout << "Yes" << endl;
}

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

B.建筑公司

首先可以记录一下当前公司有的各类员工人数
然后再将项目人数大于公司现有各类员工人数的记录一下 并且将此项目+n 表示所需的n类的员工不够
然后再记录一下完成后会带来的员工人数 并且将能直接完成的项目入队
然后就是再队列中不断更新现有员工人数 并且每一项员工人数够就入队

code:

#include<bits/stdc++.h>
#define endl '\n'
#define int long long 

using namespace std; 

typedef pair<int,int> PII;
const int N = 1e5 + 7;
int st[N];//记录每一个项目有几个工人不满足当前公司现有情况 

void solve(){
    int g; cin >> g;
    map<int,int> now;
    for(int i = 1;i <= g;i ++){
        int t,u; cin >> t >> u;
        now[t] += u;
    }
    int n; cin >> n;
    map<int,priority_queue<PII,vector<PII>,greater<PII>>> suf;//不满足当前员工人数的项目的所差数 
    map<int,vector<PII>> add;
    queue<int> q;
    for(int i = 1;i <= n;i ++){
        int m1; cin >> m1;
        for(int j = 1;j <= m1;j ++){
            int a,b; cin >> a >> b;
            if(now[a] >= b) continue;
            suf[a].push({b,i});
            st[i] ++; 
        }
        int m2; cin >> m2;
        for(int j = 1;j <= m2;j ++){
            int c,d; cin >> c >> d;
            add[i].push_back({c,d}); 
        }
        if(!st[i]) q.push(i);
    }
    int ans = 0;
    while(q.size()){
        auto t = q.front();
        q.pop();
        ans ++;
        for(auto x : add[t]){
            now[x.first] += x.second;
            while(suf[x.first].size()){
                if(suf[x.first].top().first > now[x.first]) break;
                st[suf[x.first].top().second] --;
                if(!st[suf[x.first].top().second]) q.push(suf[x.first].top().second);
                suf[x.first].pop();
            }
        }
    }
    cout << ans << endl; 
}

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

D.负重越野

二分答案x
那么vi - (wj - wi) >= x 即 vi + wi - x >= wj
所以check就可以:

  • 将 vi >= x 存一块 存为 vi + wi - x 命名为 1
  • 将vi < x 存一块 命名为 2

然后sort后分别比较 1 和 2 最大的 看是否可以符合二分的答案 x

code:

#include<bits/stdc++.h>
#define int long long

using namespace std;

const int N = 1e5 + 7;
pair<int,int> p[N];
int st[N]; 
int n;

int check(int x){
    vector<int> v1,v2;  
    for(int i = 0;i < n;i ++){
        if(p[i].first >= x) v1.push_back(p[i].first + p[i].second - x);
        else v2.push_back(p[i].second);
    }
    sort(v1.begin(),v1.end());
    sort(v2.begin(),v2.end());
    if(v2.size() > v1.size()) return 0;
    int len1 = v1.size(),len2 = n - len1;
    for(int i = len1 - 1;i >= 0;i --){
        if(!len2) break;
        len2 --;
        if(v1[i] < v2[len2]) return 0;
    }
    return 1;
} 

void solve(){
    cin >> n;
    for(int i = 0;i < n;i ++) cin >> p[i].first >> p[i].second;
    sort(p,p + n);
    int l = -1,r = p[n - 1].first + 1;
    while(l + 1 != r){
        int mid = l + r >> 1;
        if(check(mid)) l = mid;
        else r = mid;
    } 
    cout << l << endl;
}

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

E.数学问题

易看出应该先除后乘 不然乘的最后会被除掉 (n * k + x) / k = n * k / k + x / k (x < k) = n
然后枚举次数即可 并且乘时候看一下边界即可知道有无m的倍数 取最小val

code:

#include<bits/stdc++.h>
#define int long long

using namespace std;

void solve(){
    int n,k,m,a,b; cin >> n >> k >> m >> a >> b;
    if(n % m == 0){
        cout << 0 << endl;
        return;
    }
    if(k == 1){
        cout << -1 << endl;
        return;
    }
    int mn = 1e18;
    for(int i = 0;;i ++){
        if(n == 0){
            mn = min(mn,i * b);
            break;
        }
        int cnt = i * b;
        __int128 l = n,r = n;
        while(l % m && l / m == r / m){
            cnt += a;
            l = l * k;
            r = r * k + (k - 1); 
        }
        mn = min(mn,cnt);
        n = n / k;
    }
    cout << mn << endl;
}

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

G.匹配

i - j = ai - aj
显而易见可以变化为 ai - i =
aj - j
即 ai - i 值相同的可以匹配
那么就可以算出所有的 ai - i 然后sort后从最大的开始 两两相同的去匹配 只要匹配后的值 > 0 就可以算入答案 最后得到最大值

code:

#include<bits/stdc++.h>
#define int long long

using namespace std;

const int N = 1e5 + 7;
int a[N];
pair<int,int> p[N];
int n;

void solve(){
	cin >> n;
	for(int i = 1;i <= n;i ++){
		cin >> a[i];
		int cnt = a[i] - i;
		p[i] = {cnt,a[i]};
	}
	sort(p + 1,p + 1 + n);
	int sum = 0;
	for(int i = n;i >= 1;){
		if(i - 1 < 1) break;
		if(p[i].first != p[i - 1].first){
			i --;
			continue;
		}
		int cnt = p[i].second + p[i - 1].second;
		if(cnt > 0) sum += cnt;
		i -= 2;
	}
	cout << sum << endl;
}

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

I.三只骰子

直接三个for循环枚举看是否有符合题目要求的答案

code:

#include<bits/stdc++.h>
#define int long long

using namespace std;

int a[6] = {1,4,2,3,5,6};

void solve(){
	int A,B; cin >> A >> B;
	for(int i = 0;i < 6;i ++){
		for(int j = 0;j < 6;j ++){
			for(int k = 0;k < 6;k ++){
				int x = 0,y = 0;
				if(i < 2) x += a[i];
				else y += a[i];
				if(k < 2) x += a[k];
				else y += a[k];
				if(j < 2) x += a[j];
				else y += a[j];
				if(x == A && y == B){
					cout << "Yes" << endl;
					return; 
				}
			}
		}
	}
	cout << "No" << endl;
}

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

L.谜题:曲尺

直接以给出的(bi,bj)为对角线向其左上和右下套L,一直到无法向左上或者右下放L时,那么看他所处位置,判断是只往右上放还是往左下方即可

code:

#include<bits/stdc++.h>
#define int long long

using namespace std;

int n;
int x,y; 

void solve(){
    cin >> n >> x >> y;
    int cnt = 1;
    int x1,x2,y1,y2;
    x1 = x2 = x;
    y1 = y2 = y;
    int x3,y3;
    int nw = 1;
    cout << "Yes" << endl << n - 1 << endl;
    for(int i = 0;i < n - 1;i ++){
        if(x1 > 1 && y1 > 1){
            x1 --,y1 --;
            cout << x1 << " " << y1 << " ";
            cout << cnt << " " << cnt << endl; 
        } else if(x2 < n && y2 < n){
            x2 ++,y2 ++;
            cout << x2 << " " << y2 << " ";
            cout << "-" << cnt << " -" << cnt << endl; 
        } else if(x1 == 1 && y2 == n){
            cout << x2 + nw  << " " << y1 - nw << " ";
            cout << "-" << cnt << " " << cnt << endl;  
            nw ++;
        } else if(y1 == 1 && x2 == n){
            cout << x1 - nw << " " << y2 + nw << " ";
            cout << cnt << " -" << cnt << endl; 
            nw ++;
        } 
        cnt ++;
    } 
}

signed main(){
	ios::sync_with_stdio(false);
	cin.tie(nullptr),cout.tie(nullptr);
	int t; t = 1;
	while(t --){
		solve();
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值