题目大意:
给出你n条边,进行q次操作,每次 去一跳对应长度的边,问每次让你从中选出8个,其中4个组成正方形,另外4个组成长方形(可以是正方形)。是否没选出这8个。
分析一下:
其中他要让你组成一个正方形,那么肯定要有至少1组4个相等的边,长方形的话就是 两两相等,也可以四个都相等,那么我们就可以分出类了。
言而终止总而言之也就这样四种。
那么我们来想,先把4个一组的调出来,这样可以直接判断是否能够组成正方形,在上一步的基础上再把成双成对的拿出来,这样为了长方形的两条对边。
具体看下注释就应该差不多了。
#include <map>
#include <queue>
#include <string>
#include<iostream>
#include<stdio.h>
#include<string.h>
#include <algorithm>
#include <math.h>
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
typedef pair<ll,ll> pii;
#define mem(a,x) memset(a,x,sizeof(a))
#define debug(x) cout << #x << ": " << x << endl;
#define rep(i,n) for(int i=0;i<(n);++i)
#define repi(i,a,b) for(int i=int(a);i<=(b);++i)
#define repr(i,b,a) for(int i=int(b);i>=(a);--i)
const int maxn=2e5+1010;
#define inf 0x3f3f3f3f
#define sf scanf
#define pf printf
const int mod=998244353;
const int MOD=10007;
inline int read() {
int x=0;
bool t=false;
char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=true,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return t?-x:x;
}
/*
vector<ll> m1;
vector<ll> m2;
priority_queue<ll , vector<ll> , greater<ll> > mn;//上 小根堆 小到大
priority_queue<ll , vector<ll> , less<ll> > mx;//下 大根堆 大到小
*/
map<ll,ll>mp;
map<ll,ll>mpp;
ll n,m,t,l,r,p;
ll sum,ans,res,cnt,flag,maxx,minn;
bool isprime[maxn];
ll a[maxn],b[maxn],cc[maxn];
ll dis[maxn],vis[maxn];
ll dp[1010][1010];
string str,s;
#define read read()
int main(){
n=read;
for(int i=1;i<=n;i++){
sf("%lld",&a[i]),mp[a[i]]++;
}
sort(a+1,a+1+n);//为了之后的去重操作
for(int i=1;i<=n;i++){
if(a[i]!=a[i-1]){//出来个新的
mpp[a[i]]=++cnt;//把a[i]标记出下标
sum+=mp[a[i]]/4;//成4的挑出来
mp[a[i]]=mp[a[i]]%4;//剩余不足4的
dis[cnt]=mp[a[i]]/2;//在剩余不足4的基础上 挑出成双成对的。
ans+=dis[cnt];// 总的成双成对的
}
}
m=read;
while(m--){
char c;
cin>>c>>p;
if(c=='+'){
mp[p]++;//新来加上
sum+=mp[p]/4;//成4 +1
mp[p]=mp[p]%4;//成4 归零
if(mp[p]==0) ans--,dis[mpp[p]]=0;//归零 原本加的3中的一对让4拿跑了就得减1
else if(mp[p]==2){// 新成双, 从1变成2 多出一对
ans++;
dis[mpp[p]]=2;
}else {
dis[mpp[p]]=mp[p]/2;
}
if(sum>=2||(sum==1&&ans>=2)){//这就是判断条件 sum>=2 两个成4的(正方形) 或者 一4一2(一正一长)
cout<<"YES"<<endl;
}else cout<<"NO"<<endl;
}else {
if(mp[p]==0){//原零 出4
sum--;
mp[p]=3;
}else {
mp[p]--;
}
if(mp[p]==1) ans--,dis[mpp[p]]=1;//原有2中的一对取走,成双成对减1,
else if(mp[p]==3){//原本4中的一组拆出来,就多出3中的 一对加上
ans++;
dis[mpp[p]]=3;
}else {
dis[mpp[p]]=mp[p]/2;
}
if(sum>=2||(sum==1&&ans>=2)){//同上
cout<<"YES"<<endl;
}else {
cout<<"NO"<<endl;
}
}
}
return 0;
}
在这里说一个我一开始错误的地方。
unordered_map<int,int>mp;
int a[maxn];///
bool check(){
if(a[8]) return 1;
if((a[6]||a[7]||a[8])&&(a[2]||a[3]||a[4]||a[5]||a[6]>=2||a[7]>=2||a[8]>=2)) return 1;
if((a[4]||a[5]||a[6]||a[7]||a[8])&&(a[2]>=2||a[3]>=2||a[4]>=3||a[5]>=3||a[6]>=3||a[7]>=3||a[8]>=3)) return 1;
if(a[4]>=2||a[5]>=2||a[6]>=2||a[7]>=2||a[8]>=2) return 1;
return 0;
}
int main(){
int n=read();
for(int i=1;i<=n;i++){
int x=read();
mp[x]++;
}
for(auto it:mp){
int t=it.second;
t=min(t,8);
a[t]++;
}
int q=read();
while(q--){
char op[2];
cin>>op;int x=read();
if(*op=='+'){
a[mp[x]]--;
mp[x]=min(mp[x]+1,8);
a[mp[x]]++;
}
else{
a[mp[x]]--;
mp[x]=min(mp[x]-1,8);
a[mp[x]]++;
}
if(check()) puts("YES");
else puts("NO");
}
return 0;
}
这里错了一点,就是。
不论他原本多大最后你都取了min(x,8),这样最后都归了8,那么这样就导致之后减1条边的时候,他会把本应是x-1的,变成7,这样就会影响结果了。
卑微求赞(深夜拖着肚子疼的身体,抹着眼泪写完了。)
肚子疼是真的,抹眼泪当然是假的啦。哈哈哈哈