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,可以保证一定在前 种,但不一定是严格降序的,故对这些满足条件的再做一次排序即可。
但是也可以尝试枚举前两种蛋糕的所有组合,取前 种,再用这 种进一步和第三种蛋糕去组合,再取前 种即可。
代码:
#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是一样的题,我都不会
代码:不会