2020上海大学校赛H 纸牌游戏(思维+暴力)

首先肯定是想着贪心选越大越好,问题是如何去检查当前选这个是否满足题意。我们可以对后面的进行判断

已知当前的余数是t,那么我们要检查3-t能否通过后面的组合选到,因为现在有3种数,我们考虑先固定一个数。

那么剩下两个数就是两个变量,并且需要满足两个等式,因此我们可以将1个变量通过约束条件算出他的等式。

之后我们控制这个变量的枚举范围看他能否成功。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+10;
string s;
int ans[N];
int cnt[3];
int num[10];
bool check(int sign,int tot){
    int i;
    int a=cnt[0],b=cnt[1],c=cnt[2];
    int l=max(0,tot-b-c),r=min(a,tot);//0使用的范围
    for(i=l;i<=r;i++){
        int y=((2*tot-2*i-sign)%3+3)%3;//1要满足的条件
        int l0=max(0,tot-i-c),r0=min(b,tot-i);//1使用的范围
        while(l0%3!=y) l0++;
        if(l0<=r0)
            return true;
    }
    return false;
}
int main(){
    ios::sync_with_stdio(false);
    int t,k;
    cin>>t;
    while(t--){
        memset(cnt,0,sizeof cnt);
        memset(ans,0,sizeof ans);
        memset(num,0,sizeof num);
        int i;
        cin>>s>>k;
        int tmp=0;
        for(i=0;i<(int)s.size();i++){
            int sign=s[i]-'0';
            cnt[sign%3]++;
            num[sign]++;
        }
        int id=0;
        for(i=9;i>=0&&id<k;i--){
            while(id<k&&num[i]){
                int sign=(i+tmp)%3;
                cnt[i%3]--,num[i]--;
                if(!check((3-sign)%3,k-id-1)){
                    cnt[i%3]++;
                    num[i]++;
                    break;
                }
                ans[++id]=i;
                tmp=sign;
            }
        }
        if((ans[1]==0&&id>1)||id<k){
            cout<<-1<<endl;
        }
        else{
            for(i=1;i<=k;i++)
                cout<<ans[i];
            cout<<endl;
        }
    }
}
View Code
没有人不辛苦,只有人不喊疼
原文地址:https://www.cnblogs.com/ctyakwf/p/13648614.html