首先肯定是想着贪心选越大越好,问题是如何去检查当前选这个是否满足题意。我们可以对后面的进行判断
已知当前的余数是t,那么我们要检查3-t能否通过后面的组合选到,因为现在有3种数,我们考虑先固定一个数。
那么剩下两个数就是两个变量,并且需要满足两个等式,因此我们可以将1个变量通过约束条件算出他的等式。
之后我们控制这个变量的枚举范围看他能否成功。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#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; } } }