题目描述:
有一串数An,选出其中的子串,子串的和必须是3的倍数,且子串经过排列成为一个数字后,必须是所有可能的子串中最大的。
比如[ 1,2,3,4,5]我们直接选出54321级符合要求,3不是最大的。
稍稍吐槽一下,这道题是cf的原题。以前在cf上做用的贪心,刷刷刷就出来了,但是在这里惯性思维用了DP做。其实DP也没问题,关键这里的难点是需要打印最大的串。
解题思路:
我们令dp[pos][no]表示对当前前面所有项求和模3为no时,最长的符合要求的串是什么。为什么我们要求最长的符合要求的串呢?因为我们必须返回最大的数字,所以越长越大。
转移:
cur代表本次的数字.
代表的是本个数是否应该选。
最后我们可以得出最长串,最后的问题是怎么得到选哪个数字呢,这里我们需要贪心的思想,首先输入的数字从大到小排序,若
dp[pos+1][(no+cur)%3]==dp[pos][no]-1,证明本次是可以要的! 那么我们就尽可能地把它拿过来。
const int MAXN=1e4+10;
const int inf=1e9;
class Solution {
public:
vector<int> arrmv;
int dfs(int pos,int modn){
if(pos==n && modn>0)return -inf;
if(pos==n)return 0;
if(dp[pos][modn]!=-1)return dp[pos][modn];
int lv=dfs(pos+1,(modn+arrmv[pos])%3)+1;
int rv=dfs(pos+1,modn);
if(lv>rv)choice[pos][modn]=1;
else choice[pos][modn]=0;
return dp[pos][modn]=max(lv,rv);
}
int n;
vector<vector<int>> dp;
vector<vector<int>> choice;
string largestMultipleOfThree(vector<int>& digits) {
sort(digits.begin(),digits.end(),greater<int>());
arrmv=digits;
//for(auto it:arrmv)cout<<it<<" ";
dp.assign(MAXN,vector<int>(3,-1));
choice.assign(MAXN,vector<int>(3,-1));
n=digits.size();
dfs(0,0);
//cout<<dp[0][0]<<endl;
if(dp[0][0]<=0)return string("");
vector<int> mv;
int ls;
for(int i=0;i<n;i++){
if(!i)ls=0;
if(i==n-1){
if((arrmv.back()+ls)%3==0)mv.push_back(arrmv.back());
break;
}
if(dp[i+1][(ls+arrmv[i])%3]==dp[i][ls]-1){
//cout<<"pick "<<i<<endl;
ls+=arrmv[i];
ls%=3;
mv.push_back(arrmv[i]);
}
}
sort(mv.begin(),mv.end(),greater<int>());
string ret("");
int zf=1;
for(auto it:mv){
if(it>0)zf=0;
ret+=it+'0';
}
if(zf)return string("0");
return ret;
}
};