cf 1474 C. Array Destruction(暴力,数据结构)

题目链接:https://codeforces.ml/contest/1474/problem/C

题意:T组样例(T<=1000),每一组样例输入n(1<=n<=1000),然后输入一个长度为2*n的数组a,(1<=ai<=1e6)。

然后问是否满足条件,如果满足先打印"YES",然后输入最先取出的两个数的和,再每一次取出两个数,满足和与上一次取出的两个数中的最大值相等,如果能一直取到一个数都不剩,则满足条件,否则打印"NO"。

示例:

input:::
4
2
3 5 1 2
3
1 1 8 8 64 64
2
1 1 2 4
5
1 2 3 4 5 6 7 14 3 11
output:::
YES
6
1 5
2 3
NO
NO
YES
21
14 7
3 11
5 6
2 4
3 1

 

题解/总结:

1.set<ll,greater<ll> > st;表示大优先集合;st.begin()只是迭代器;st配合数组或者mp是可以模拟multiset的。最次取最大值可以*st.begin(),(如果边取边删的话)不要for(auto i:st)。

2.哎,竟然没注意到所有N的和不大于1000,所以没敢暴力。许久没打cf了,还是因为在家里不习惯??总犯一些很傻的错误。

3.多写函数,方便直接调用!!!!!!!!!!!

4.最大值一定能作为mx,每次只能从剩下的最大值作为mx开始,所以如果开始确定了选的另一个数,那么删除方法就是固定的了,只需要再判断是否能按照这个删除方法删除。

5.直接暴力,时间复杂度大概O(nlogn*nlogn)

代码:

#include <bits/stdc++.h>

#define ll int
#define pi acos(-1)
#define pb push_back
#define mst(a, i) memset(a, i, sizeof(a))
#define pll pair<ll, ll>
#define fi first
#define se second
#define mp(x,y) make_pair(x,y)
#define rep(i,a,n)  for(ll i=a;i<=n;i++)
#define per(i,n,a)  for(ll i=n;i>=a;i--)
#define dbg(x) cout << #x << "===" << x << endl
#define dbgg(l,r,x) for(ll i=l;i<=r;i++) cout<<x[i]<<" ";cout<<"<<<"<<#x;cout<<endl

using namespace std;

template<class T>void read(T &x){T res=0,f=1;char c=getchar();while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}while(isdigit(c)){res=(res<<3)+(res<<1)+c-'0';c=getchar();}x=res*f;}
void print(ll x){if(x<0){putchar('-');x=-x;}if(x>9)print(x/10);putchar(x%10+'0');}
const ll maxn = 1e6 + 10;
const ll mod = 1e9+7;

ll n,a[maxn];
set<ll,greater<ll> > st;
unordered_map<ll,ll> val;
bool cmp(ll a,ll b){
    return a>b;
}
bool ok(ll id){//判断最开始取a[1]和a[id]的时候是否能取完 
    ll mx=a[1];//上一次取的两个数中的最大值 
    val[a[1]]--;if(val[a[1]]==0) st.erase(a[1]);
    val[a[id]]--;if(val[a[id]]==0) st.erase(a[id]);
    while(st.size()){
    	ll i=*st.begin();//每次取st中最大值 
        if(val[mx-i]==0||(2*i==mx&&val[i]<2)) break;//取不到直接false 
        else{
        	//取i,mx-i 
            val[mx-i]--;if(val[mx-i]==0) st.erase(mx-i);
            val[i]--;if(val[i]==0) st.erase(i);
            mx=max(i,mx-i);
        }
    }
    if(st.size()==0) return true;
    return false;
}
void add(){
    val.clear();
    st.clear();
    rep(i,1,2*n){
        val[a[i]]++;
        if(a[i]!=a[i-1]) st.insert(a[i]);//防止重复 
    }
}
void Print(ll a,ll b){//打印两个数 
    print(a),putchar(' '),print(b),puts(""); 
}
void solve(ll id){//"YES"时输出答案 ,与判断步骤一致 
    ll mx=a[1];
    val[a[1]]--;if(val[a[1]]==0) st.erase(a[1]);
    val[a[id]]--;if(val[a[id]]==0) st.erase(a[id]);
    Print(a[1],a[id]); 
    while(st.size()){
    	ll i=*st.begin();
        if(val[mx-i]==0||(2*i==mx&&val[i]<2)) break;
        else{
            val[mx-i]--;if(val[mx-i]==0) st.erase(mx-i);
            val[i]--;if(val[i]==0) st.erase(i);
            Print(i,mx-i);mx=max(i,mx-i);
        }
    }
}
int main() {
    ll _s = 1;
    read(_s);
    //freopen("testdata.in","r",stdin);
	//freopen("testout.out","w",stdout);
    for (ll _=1;_<=_s;_++) {
        read(n);
        rep(i,1,2*n) read(a[i]);
        sort(a+1,a+1+2*n,cmp);
        ll p=0;//删除id的时候满足条件 
        a[0]=-1;//防止重复 
        rep(i,2,2*n){
             if(a[i]==a[i-1]&&i!=2) continue;
            add();
            if(ok(i)){
                p=i;break;//找到就跳出 
            }
        }
        if(p==0) puts("NO");
        else{
            puts("YES");
            cout<<a[1]+a[p]<<endl;
            add();
            solve(p);
        }  
    }
    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值