2023牛客暑期多校训练营5

之前落下的每一场比赛都是要补回来的。。。
G Go to Play Maimai DX
题解的想法比较简单,由于找到满足1,2,3出现至少一次,4出现至少k次的最短区间,所以可以双指针,双指针用于这种长度最短,长度越长越容易满足条件的题就很恰当。
我没想到双指针,就写的比较麻烦,预处理每个数后一个1,2,3的位置,以及4的特殊处理,每次枚举左端点,计算右端点即可。

点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define db double
#define endl '\n'
#define rep(x,y,z) for(int x=y;x<=z;++x)
#define fep(x,y,z) for(int x=y;x>=z;--x)
using namespace std;
const int N=1e5+10;
int n,k,a[N],nex[N][5],pl[5],p[N],ct[N],tot; 

int main()
{
//	freopen("1.in","r",stdin);
	ios::sync_with_stdio(0);
	cin.tie(0);cout.tie(0);
	cin>>n>>k;
	rep(i,1,n) cin>>a[i];
	rep(i,1,3) pl[i]=n+1;
	fep(i,n,1)
	{
		rep(j,1,3) nex[i][j]=pl[j];
		pl[a[i]]=i;
		ct[i]=tot;
		if(a[i]==4)
		{
			p[++tot]=i;
			ct[i]=tot;
		}
	}
	int ans=n;
	rep(i,1,n)
	{
		int mx1=max(max(nex[i][1],nex[i][2]),nex[i][3]);
		if(mx1==n+1) continue;
		if(ct[i]<k) continue;
		mx1=max(mx1,p[ct[i]-k+1]);
		ans=min(ans,mx1-i+1); 
	}
	cout<<ans<<endl;
	return 0;
}

D Cirno's Perfect Equation Class
没啥难度,按照题意模拟,暴力枚举c的所有因子即可。

C Cheeeeen the Cute Cat
有意思的题目,题目让你明求最大匹配,那么说明正解要么和二分图没关系(大概率),要么就是二分图匹配算法上做一些优化。
其实题目已经提示的很明显了,当提到i和i+n无边,i和i+n,j和j+n之间只能存在一条边时,这就提示我们要将i和i+n合并看,而且题目规定边数为n*(n-1)/2,这个数字也很特殊,不就是完全图吗?合并的时候就有一个问题,考虑方向吗?这个时候我们就要观察二分图的匹配在合并时的特点,发现如果合并时按照无向边合并,则无法有效区分是i到j+n的连边还是j到i+n的连边,所以为了区分,按照有向的合并,i到j+n表示i到j有边,这个时候合并起来的图就是一个竞赛图,之后继续考虑匹配在合并后的图上的体现,简单手玩之后可以发现,一系列的匹配在合并后的图上体现为一些路径,也就是说我们要在新图上选择若干条互不相交的路径,这个时候就需要用到一些性质了。竞赛图必有哈密顿路径,所以答案至少为n-1,接下来只需要考虑答案什么时候是n,即存在哈密顿回路。对于有向图的一个点数大于等于3的强连通分量,肯定存在哈密顿环,(图中不存在强连通分量个数为2的)。即只需要判掉个数为1的强连通分量即可。

点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define db double
#define endl '\n'
#define rep(x,y,z) for(int x=y;x<=z;++x)
#define fep(x,y,z) for(int x=y;x>=z;--x)
using namespace std;
const int N=3010;
int n,du[N];

inline bool check()
{
	rep(i,1,n) rep(j,1,n)
	{
		if(i!=j&&du[i]+du[j]<n) return false;	
	} 
	return true;
}

int main()
{
//	freopen("1.in","r",stdin);
	ios::sync_with_stdio(0);
	cin.tie(0);cout.tie(0);
	cin>>n;
	rep(i,1,n) rep(j,1,n)
	{
		int x;cin>>x;
		du[i]+=x;
	}
	sort(du+1,du+n+1);
	int j=0,s=0;
	rep(i,1,n)
	{
		s+=du[i];
		if(s==i*(i-1)/2)
		{
			if(i-j<3) 
			{
				cout<<n-1<<endl;
				return 0;
			}
			j=i;
		}
	}
	cout<<n<<endl;
	
	return 0;
}

H Nazrin the Greeeeeedy Mouse
挺有意思的DP。
首先观察数据发现数据特征n,ai,size都很小,但m很大,考虑每一轮可以拿多个奶酪,所以200个奶酪最多有200轮是有用的,所以直接从m中取后n个最大的size即可。
首先想到的是DP,用f[i][j]表示前i个奶酪,用到第j轮的最大吃到的美味值。
发现转移的时候缺少某个个区间用某个size的最大美味值的信息,故这个信息也需要DP。
根据要求,设g[i][j][k]表示从i到j用k的大小,最多迟到的美味值。
转移的话,g[i][j][k]=max(g[i][j-1][k],g[i][j-1][k-a[j]);
总复杂度n^3.

点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define db double
#define endl '\n'
#define rep(x,y,z) for(int x=y;x<=z;++x)
#define fep(x,y,z) for(int x=y;x>=z;--x)
using namespace std;
const int N=210,M=1e5+10;
int n,m,a[N],b[N],g[N][N][N],f[N][N],sze[M];

int main()
{
// 	freopen("1.in","r",stdin);
	ios::sync_with_stdio(0);
	cin.tie(0);cout.tie(0);
	cin>>n>>m;
	rep(i,1,n) cin>>a[i]>>b[i];
	rep(i,1,m) cin>>sze[i];
	int t=min(m,n);
	sort(sze+1,sze+m+1,[&](int a,int b){return a>b;});
	reverse(sze+1,sze+t+1);
	rep(i,1,n) rep(j,i,n) rep(k,0,sze[t])
	{
		g[i][j][k]=g[i][j-1][k];
		if(k>=a[j]) g[i][j][k]=max(g[i][j][k],g[i][j-1][k-a[j]]+b[j]);	
	}
//	cout<<g[1][1][3]<<' '<<g[2][4][7]<<endl;
	//前i个奶酪用到当前第j个口袋. 
	rep(i,1,n) rep(j,1,t)
	{
		rep(k,1,i) f[i][j]=max(f[i][j],f[k-1][j-1]+g[k][i][sze[j]]); 
	}
	cout<<f[n][t]<<endl;	 
	return 0;
}

E Red and Blue and Green

posted @ 2023-08-02 18:03  逆天峰  阅读(22)  评论(0编辑  收藏  举报
作者:逆天峰
出处:https://www.cnblogs.com/gcfer//