Codeforces Round 866 (Div. 2)

Problem - C - Codeforces

思路:

  1. 如果当前排列存在mex+1,我们显然需要删除所有mex+1,所以需要把mex+1最早到最晚所包含的区间可以全部改为mex
  2. 如果不存在,如果a数组所有数一个也不重复且都小于mex,此时mex=n(mex对于排列能取到的最大值),无法修改。如果mex<n,说明一定有小于mex的数重复或者有数大于mex(不是mex+1,排除了),那么一定可以修改(把重复或者大的这个点改成mex)
  3. 我们进行了尽可能“合理”修改后,再算一遍mex,如果变成mex+1则成功,否则失败
#include <bits/stdc++.h>
using namespace std;
#define ll               long long
#define endl             "\n"
#define int              long long
#define endll            endl<<endl
typedef unsigned long long ull;
typedef pair<int, int> pii;
typedef pair<long long, long long> pll;
//---------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------//
//double 型memset最大127,最小128
const int INF = 0x3f3f3f3f;         //int型的INF
const ll llINF = 0x3f3f3f3f3f3f3f3f;//ll型的llINF
const int N = 2e5 + 10;
int a[N];
int n;
int MEX()
{
	map<int,int>mp;
	for(int i=1; i<=n; ++i)mp[a[i]]++;
	for(int i=0; i<=n; ++i)if(!mp[i])return i;
}
void mysolve()
{
	cin>>n;
	for(int i=1; i<=n; ++i)cin>>a[i];
	int mex=MEX();
	int l=n+1,r=0;
	for(int i=1; i<=n; ++i)if(a[i]==mex+1)l=min(l,i),r=max(r,i);
	if(r)//如果有mex+1,修改区间
		{
			for(int i=l; i<=r; ++i)a[i]=mex;
			int tmp=MEX();
			if(tmp==mex+1)cout<<"YES"<<endl;
			else cout<<"NO"<<endl;
		}
	else//没有,看看是不是能修改
		{
			if(mex==n)cout<<"NO"<<endl;
			else cout<<"YES"<<endl;
		}

}

int32_t main()
{
	std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	ll t=1;
	cin >> t;
	while (t--)
		{
			mysolve();
		}
	system("pause");
	return 0;
}

Problem - D - Codeforces

思路:

  1. 因为每次只割一刀,所以显然,一定存在一片记录的是最长或者最宽,而他们就是答案(至少一个答案,至多两个)
  2. 接下来大模拟即可,记录所有片的面积和,如果我们假设的长/宽可以被整除,那么继续讨论,以长为例
    1. 如果当前sum%mx==0,我们h=mx,w=sum/mx可能成为答案,因为h是最长,所以如果有以h为边的片,一定要先减去这些片(即水平方向切)才能可能取竖直方向切(否则,本来不通过的答案可能会污染数据)
    2. 如果最后n片都能成功减去,那么该答案可以。
#include <bits/stdc++.h>
using namespace std;
#define ll               long long
#define int ll
#define endl             "\n"
typedef pair<int, int> pii;
const int N = 2e5 + 10;
int n;
bool check(int h,int w,map<int,multiset<int>> mp1,map<int,multiset<int>>mp2,bool ft)//ft标记最开始是先减去谁,如h最长,应先减w
{
	int ct=n;
	while(h>0&&w>0)
		{
			bool cnt=0;
			if(ft)
				{
					for(auto v:mp1[h])
						{
							ct--;
							w-=v;
							mp2[v].erase(mp2[v].find(h));//删除w存的片,该片已经剪过,不可重复
							cnt=1;
						}
					if(w<0)return 0;
					ft^=1;//每次减完轮流
				}
			else
				{
					for(auto v:mp2[w])
						{
							h-=v;
							ct--;
							mp1[v].erase(mp1[v].find(w));
							cnt=1;
						}
					if(h<0)return 0;
					ft^=1;
				}
			if(!cnt)return 0;
		}
	if(ct)return 0;//成功减去n片
	return 1;
}
map<int,int>mp;
void mysolve()
{
	int x,y;
	int mx=0,my=0,sum=0;
	cin>>n;
	map<int,multiset<int>>mpx,mpy;//记录每个长度/宽度可以对于的宽度/长度
	for(int i=1; i<=n; ++i)cin>>x>>y,mx=max(mx,x),my=max(my,y),mpx[x].insert(y),mpy[y].insert(x),sum+=x*y;
	int cnt=0;
	pii ans[3];
	if(sum%mx==0&&check(mx,sum/mx,mpx,mpy,1))ans[++cnt]= {mx,sum/mx};
	if(sum%my==0&&sum/my!=mx&&check(sum/my,my,mpx,mpy,0))ans[++cnt]= {sum/my,my};
	cout<<cnt<<endl;
	for(int i=1; i<=cnt; ++i)cout<<ans[i].first<<" "<<ans[i].second<<endl;
}

int32_t main()
{
	std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	ll t=1;
	cin >> t;
	while (t--)
		{
			mysolve();
		}
	system("pause");
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值