CF-662-B

题目大意:

给出你n条边,进行q次操作,每次 / 加/减 去一跳对应长度的边,问每次让你从中选出8个,其中4个组成正方形,另外4个组成长方形(可以是正方形)。是否没选出这8个。

分析一下:

其中他要让你组成一个正方形,那么肯定要有至少1组4个相等的边,长方形的话就是 两两相等,也可以四个都相等,那么我们就可以分出类了。
a a a a a a a a aaaaaaaa a a a a b b b b aaaabbbb a a a a a a b b aaaaaabb a a a a b b c c aaaabbcc
言而终止总而言之也就这样四种。
那么我们来想,先把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,这样就会影响结果了。

卑微求赞(深夜拖着肚子疼的身体,抹着眼泪写完了。)
肚子疼是真的,抹眼泪当然是假的啦。哈哈哈哈

猜你喜欢

转载自blog.csdn.net/weixin_45911397/article/details/107873622
今日推荐