2023年广东省程序设计大赛

C

双指针,排序

买便宜的,用最贵的卖出

cpp 复制代码
#include<bits/stdc++.h>

using namespace std;
#define int long long
const int N = 2e5 + 10;
int n,m;
int re[2]={1,4};
int bl[4]={2,3,5,6};
int f;
struct node
{
	int x,y;
}a[N];
bool cmp(node W,node Q)
{
	return W.x<Q.x;
}
void solve()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	{
//		cin>>a[i].x>>a[i].y;
		scanf("%d%d",&a[i].x,&a[i].y);
	}
	sort(a+1,a+n+1,cmp);
	int ans=0;
	int l=1,r=n;
	while(l<r)
	{
		int k=min(a[l].y,a[r].y);
		ans+=k*(a[r].x-a[l].x);
		a[r].y-=k;
		a[l].y-=k;
		if(a[r].y==0) r--;
		if(a[l].y==0) l++;
	}
	cout<<ans<<endl;
}
signed main()
{
	int T;
	cin>>T;
	while(T--)
		solve();
	return 0;
} 

K

爆搜+回溯

cpp 复制代码
#include<bits/stdc++.h>

using namespace std;
#define int long long
const int N = 2e5 + 10;
int n,m,k;
int a[30][30];
int f[][2]={{0,2},{0,-2},{2,0},{-2,0}};
int ff[][2]={{0,1},{0,-1},{1,0},{-1,0}};
int minn=6;
void dfs(int c)
{
	minn=min(minn,c);
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			if(a[i][j])
			{
				for(int k=0;k<4;k++)
				{
					int dx=i+f[k][0],dy=j+f[k][1];
					int tx=i+ff[k][0],ty=j+ff[k][1];
					
					if(dx>=1&&dx<=n&&dy>=1&&dy<=m&&a[tx][ty]==1&&a[dx][dy]==0)
					{
						a[i][j]=0;
						a[dx][dy]=1;
						a[tx][ty]=0;
						
						dfs(c-1);
						
						a[i][j]=1;
						a[dx][dy]=0;
						a[tx][ty]=1;						
						
					}
				}
			}
		}
	}
}
void solve()
{
	memset(a,0,sizeof a);
	minn=6;
	cin>>n>>m>>k;
	for(int i=1;i<=k;i++)	
	{
		int x,y;
		cin>>x>>y;
		a[x][y]=1;
	}
	dfs(k);
	cout<<minn<<endl;
}
signed main()
{
	int T;
	cin>>T;
	while(T--)
		solve();
	return 0;
} 

注意python中global的运用

python 复制代码
f = [[0, 2], [0, -2], [2, 0], [-2, 0]]
ff = [[0, 1], [0, -1], [1, 0], [-1, 0]]

def dfs(c):
    global minn  # 声明使用全局变量
    minn = min(minn, c)
    for i in range(1, n + 1):
        for j in range(1, m + 1):
            if a[i][j] == 1:
                for k in range(4):
                    dx, dy = i + f[k][0], j + f[k][1]
                    tx, ty = i + ff[k][0], j + ff[k][1]

                    if dx >= 1 and dx <= n and dy >= 1 and dy <= m and a[tx][ty] == 1 and a[dx][dy] == 0:
                        a[i][j] = 0
                        a[dx][dy] = 1
                        a[tx][ty] = 0

                        dfs(c - 1)

                        a[i][j] = 1
                        a[dx][dy] = 0
                        a[tx][ty] = 1

T = int(input())

while T:
    T -= 1

    n, m, k = map(int, input().split())
    a = [[0 for _ in range(m + 1)] for _ in range(n + 1)]
    
    global minn
    minn = 6  # 重置 min 值
    for _ in range(k):
        x, y = map(int, input().split())
        a[x][y] = 1
    dfs(k)
    print(minn)

D

枚举所有邻居的数量和不是邻居的数量

假设有k个邻居,那么剩余的n-k个邻居需要2*(n-k),所以房子的个数需要大于等于2*(n-k)+k

没有只有1个邻居的可能,还有一种可能就是所有人都没有邻居,那么需要的房子数量是2*n-1

所有可能取最大值

cpp 复制代码
#include<bits/stdc++.h>

using namespace std;

#define int long long
const int N = 5e5 + 10;
int n,m,k;
struct  node
{
	int x,y;
}a[N];
int sum[N];
bool cmp(node W,node E)
{
	return W.x-W.y>E.x-E.y;
}
void solve()
{
	cin>>n>>m;
	for(int i=1;i<=n;i++) scanf("%d%d",&a[i].x,&a[i].y);
	sort(a+1,a+n+1,cmp);
	for(int i=1;i<=n;i++) sum[i]=sum[i-1]+a[i].y;
	
	int ans=a[1].x;
	int res=0;
	for(int i=2;i<=n;i++)
	{
		ans+=a[i].x;
		if(2*n-i<=m)
		{
			res=max(res,ans+sum[n]-sum[i]);
		}
	}
	
	if(2*n-1<=m)
	{
		res=max(res,sum[n]);
	}
	
	cout<<res<<endl;
}
signed main()
{
	int T;
	cin>>T;
	while(T--)
		solve();
	return 0;
} 

I

二分答案

对于不需要在图上操作的,尤其是,n*m数组太大的情况,可以使用i*m+j来存储每个点的值,

check(x)

只需要看整个图中比x小的数的坐标,只要这些小的数构成的路径满足题意(只能往右往下走)

(怎么样判断是否满足,一行一行遍历,并记录上一个点的列坐标,如果当前点的纵坐标小于上一个点的列坐标,则不满足题意,因为,当小于上一个点的列坐标,从上一个点走向当前点,上一个点只能往左走,才能走到当前点)

对于路径上其他大于x的点,不管怎么排列,x一定可以满足是这条路径最大的mex(x)

cpp 复制代码
#include<bits/stdc++.h>

using namespace std;

#define int long long
const int N = 2e6 + 10;
int n,m,k;
int a[N];
int check(int x)
{
	int last=0;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			if(a[i*m+j]<x)
			{
				if(j<last) return 0;
				last=j;
			}
		}
	}
	return 1;
}
void solve()
{
	cin>>n>>m;
	
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			int x;
			cin>>x;
			a[i*m+j]=x;
		 } 
	}
	int l=0,r=n*m;
	while(l<r)
	{
		int mid=(l+r+1)>>1;
		if(check(mid)) 
			l=mid;
		else
			r=mid-1;
	} 
	cout<<r<<endl;
}
signed main()
{
	int T;
	cin>>T;
	while(T--)
		solve();
	return 0;
} 
相关推荐
Microsoft Word1 分钟前
c++基础语法
开发语言·c++·算法
天才在此14 分钟前
汽车加油行驶问题-动态规划算法(已在洛谷AC)
算法·动态规划
一只小小汤圆26 分钟前
opencascade源码学习之BRepOffsetAPI包 -BRepOffsetAPI_DraftAngle
c++·学习·opencascade
legend_jz1 小时前
【Linux】线程控制
linux·服务器·开发语言·c++·笔记·学习·学习方法
嘿BRE1 小时前
【C++】几个基本容器的模拟实现(string,vector,list,stack,queue,priority_queue)
c++
莫叫石榴姐1 小时前
数据科学与SQL:组距分组分析 | 区间分布问题
大数据·人工智能·sql·深度学习·算法·机器学习·数据挖掘
ö Constancy2 小时前
c++ 笔记
开发语言·c++
fengbizhe2 小时前
笔试-笔记2
c++·笔记
徐霞客3202 小时前
Qt入门1——认识Qt的几个常用头文件和常用函数
开发语言·c++·笔记·qt
fpcc2 小时前
redis6.0之后的多线程版本的问题
c++·redis