思路:
- 如果当前排列存在mex+1,我们显然需要删除所有mex+1,所以需要把mex+1最早到最晚所包含的区间可以全部改为mex
- 如果不存在,如果a数组所有数一个也不重复且都小于mex,此时mex=n(mex对于排列能取到的最大值),无法修改。如果mex<n,说明一定有小于mex的数重复或者有数大于mex(不是mex+1,排除了),那么一定可以修改(把重复或者大的这个点改成mex)
- 我们进行了尽可能“合理”修改后,再算一遍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;
}
思路:
- 因为每次只割一刀,所以显然,一定存在一片记录的是最长或者最宽,而他们就是答案(至少一个答案,至多两个)
- 接下来大模拟即可,记录所有片的面积和,如果我们假设的长/宽可以被整除,那么继续讨论,以长为例
- 如果当前sum%mx==0,我们h=mx,w=sum/mx可能成为答案,因为h是最长,所以如果有以h为边的片,一定要先减去这些片(即水平方向切)才能可能取竖直方向切(否则,本来不通过的答案可能会污染数据)
- 如果最后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;
}