2024 暑假友谊赛 1

a.AtCoder abc204_d

思路:简单的动态规划问题,用dp[i][j]表示前i秒中能否凑成j,那么如果dp[i][j]==1,则可以通过dp[i][j]来更新dp[i+1][j]和dp[i+1][j+a[i+1]]=1,最后从总时间的一半向后搜索答案。

代码:

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=110,M=2e5+10;
int a[N],dp[N][M];
int n;
void solve()
{
    cin>>n;
    int sum=0;
    for(int i=1;i<=n;i++){
        cin>>a[i];sum+=a[i];
    }
    dp[0][0]=1;

    for(int i=0;i<n;i++){
        for(int j=0;j<=sum;j++){
            if(dp[i][j]!=0){
                //            cout<<i<<j<<endl;
                dp[i+1][j]=dp[i][j];
                dp[i+1][j+a[i+1]]=1;
            }
        }
    }
    int mid;
    if(sum%2!=0) mid=sum/2+1;
    else mid=sum/2;
//    cout<<sum<<endl;
    for(int i=mid;i<=sum;i++){
//        cout<<dp[n][i]<<endl;
        if(dp[n][i]){
            cout<<i<<endl;
            return ;
        }
    }
}
signed main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t = 1;
//    cin>>t;
    while (t--) {
        solve();
    }
    return 0;
}

b.AtCoder arc092_a

思路:相当于一对一的连线问题,离散数学的映射当中的满射,在这里,遍历第一遍时,我们可以记录一下,那些点之间是可以相连的,然后再逐个搜索相连状态是否合理,详见代码(相当于暴力?他们说这叫二分图最大匹配,匈牙利算法

然后还有一种贪心的方法,把红色点从小到大排序,蓝色点从大到小排序,然后对于每个红色点,找到所有满足的蓝色点中 y最小的。

代码1:


#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=110,M=2e5+10;
int n;

#define PII pair<int,int>
vector<PII>a;
vector<PII>b;
int c[220][220];//i,j,两点是否可以相连
int p[220];//当前搜索中,将已经搜到的所有点标记为1
int cnn[220];//表示每个点的对象是谁,初始对象为0,表示未连接
bool check(int x){
    for (int j=1; j<=n; j++){
        if (c[x][j]==1 && p[j]==0){
            p[j]=1;//记录搜索状态
            if (cnn[j]==0|| check(cnn[j])){//当前点未被连接或者可以转连其他点
//                cout<<x<<" "<<j<<endl;
                cnn[j]=x;
                return true;
            }
        }
    }
    return false;
}
void solve()
{
    cin>>n;
//    memset(cnn,-1,sizeof cnn);
    for(int i=1;i<=n;i++) {
        int x,y;
        cin>>x>>y;
        a.push_back({x,y});
    }
    for(int i=1;i<=n;i++){
        int x,y;
        cin>>x>>y;
        b.push_back({x,y});
    }
    for(int i=0;i<a.size();i++){
        for(int j=0;j<b.size();j++){
            if(b[j].first>a[i].first&&b[j].second>a[i].second){
                c[i+1][j+1]=1;
            }
        }
    }
    int cnt=0;
    for (int i=1; i<=n; i++)
    {
        memset(p,0,sizeof(p));
        if(check(i)){
//            cout<<i<<" "<<cnn[i]<<endl;
            cnt++;//如果成立,答案加一
        }
    }
    cout<<cnt<<endl;
}
signed main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t = 1;
//    cin>>t;
    while (t--) {
        solve();
    }
    return 0;
}

代码2:


#include <bits/stdc++.h>
using namespace std;
using i32 = int32_t;
using i64 = long long;
#define int i64
using vi = vector<int>;
using pii = pair<int, int>;
const int inf = 1e9;
signed main() {
    ios::sync_with_stdio(false), cin.tie(nullptr);
    int n;
    cin >> n;
    vector<pii> a(n), b(n);
    for (auto &[x, y]: a) cin >> x >> y;
    for (auto &[x, y]: b) cin >> x >> y;
    sort(a.begin(), a.end(), greater<>());
    sort(b.begin(), b.end());
    vi vis(n);
    for (auto &[ax, ay]: a) {
        int p = -1;
        for (int j = 0; j < n; j++) {
            if (vis[j]) continue;
            if (b[j].first <= ax or b[j].second <= ay) continue;
            if (p == -1) p = j;
            else if (p != -1 and b[j].second < b[p].second) p = j;
        }
        if (p != -1) vis[p] = 1;
    }
    cout << accumulate(vis.begin(), vis.end(), 0ll);
    return 0;
}

d.AtCoder abc123_d

思路:很简单的暴力行为,(i+1)*(j+1)*(k+1) <= K,可以保证一定在前 K 种,但不一定是严格降序的,故对这些满足条件的再做一次排序即可。

但是也可以尝试枚举前两种蛋糕的所有组合,取前 K 种,再用这 K 种进一步和第三种蛋糕去组合,再取前 K 种即可。

代码:

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=110,M=2e5+10;
int n;
int a[1005],b[1005],c[1005];
void solve()
{
    
    int x,y,z,K;
    cin >> x >> y >> z >> K;
    for(int i=0;i<x;i++) cin >> a[i];
    for(int i=0;i<y;i++) cin >> b[i];
    for(int i=0;i<z;i++) cin >> c[i];
    sort(a,a+x,greater<int>());
    sort(b,b+y,greater<int>());
    sort(c,c+z,greater<int>());
    vector<int> ans;
    for(int i=0;i<x;i++) {
        for(int j=0;j<y;j++) {
            for(int k=0;k<z;k++) {
                //选择放入不然会爆vector
                if((i+1)*(j+1)*(k+1) <= K) ans.push_back(a[i]+b[j]+c[k]);
            }
        }
    }
    sort(ans.begin(),ans.end(),greater<int>());
    for(int i=0;i<K;i++) cout << ans[i] << endl;



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

c.CodeForces 1551D1

思路:

本题是思维题,总共三种情况,n是偶,m是奇;n是奇,m是偶;n和m都是偶。

先判断最简单的n和m都是偶的情况,此时只要有偶数个横着的骨牌,就能占满桌子;但奇数个占不满。

然后判断其他两种情况,我们可以把这两种情况都先变成n和m全是偶的情况,然后用n和m均为偶数的方法判断。如果n是奇数的话,就直接让k-n/2,即先让横着的骨牌占满一行,但如果横着的骨牌还不能占满一行,即k<n/2,就一定不能占满桌子。同理,如果m是奇数的话,只要判断竖着的骨牌是否能占满一行即可。

代码:

#include<iostream>
#include<cmath>
#include<algorithm>
#include<string>
#include<string.h>
using namespace std;
typedef long long ll;
int main() {
	int T;
	cin >> T;
	while (T--) {
		bool f;
		int n, m, k;
		cin >> n >> m >> k;
		if (m & 1) {
			if (k > (m * n / 2 - n / 2)) {
				f = false;
			}
			else {
				if (!(k & 1)) {
					f = true;
				}
				else {
					f = false;
				}
			}
		}
		else {
			if (n & 1) {
				if (k >= m / 2) {
					n--;
					k -= (m / 2);
				}
				else {
					k = 1;
				}
			}
			if (!(k & 1)) {
				f = true;
			}
			else {
				f = false;
			}
		}
		if (f) {
			cout << "YES";
		}
		else {
			cout << "NO";
		}
		cout << endl;
	}
}

f.CodeForces 448D

思路:拓扑排序,二进制和热身1的h是一样的题,我都不会

代码:不会

  • 17
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值