Contest Info
Solved | A | B | C | D | E | F | G | H | I | J | K | L |
---|---|---|---|---|---|---|---|---|---|---|---|---|
6/12 | O | O | O | O | O | Ø |
- O 在比赛中通过
- Ø 赛后通过
- ! 尝试了但是失败了
- - 没有尝试
Solutions
H.纸牌游戏
题意:
每组给你一个字符串$S$和一个数字$k$
要求用$S$中的字符拼出一个长度为$k$的能被$3$整除的非负整数,不能有前导$0$.
如果无解输出$-1$,否则输出最大的答案.
思路:
我的思考方向错了直接导致实现起来很复杂,于时理所当然花了很多时间还没做出来
可以合理地想到从高到低依次枚举每一位的数,然后判断一下后面是否存在方案,问题在于如何快速判断
设还还剩下的$mod 3=0,1,2$的数个数分别为$c[0dots 2]$
设总共还需要$n$个,需要凑出$mod 3=t$的方案
这时后我们假设枚举某一个,比如我们枚举$0$选了$i$个,设还剩下$n-i$个要选,设剩下两个选了$x,y$个,则有限制条件
$$x+y=n-i,2x+y = t(mod 3)$$
把$x$消掉,得到
$$2n-2i-2y+y=t (mod 3)->y=2n−2i−t(mod3)$$
我们可以根据各种限制条件解出$y$的可行区间,然后判断区间内是否存在一个$y$即可
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn = 1e5+100; int T, n, m, cnt[10], cntmod[3]; char s[maxn]; bool judge(int x, int m){ if(!m) return !x; int a = cntmod[0], b = cntmod[1], c = cntmod[2]; int l0 = max(0, m-b-c), r0 = min(a, m); for(int i = l0; i <= r0; i++){ int t = ((2*(m-i)-x)%3+3)%3; int l1 = max(0, m-i-c), r1 = min(b, m-i); while(l1%3!=t) l1++; if(l1<=r1) return true; } return false; } int main(){ scanf("%d", &T); while(T--){ scanf("%s%d", s+1, &m); for(int i = 0; i < 3; i++) cntmod[i] = 0; for(int i = 0; i <= 9; i++) cnt[i] = 0; int len = strlen(s+1); for(int i = 1;i<=len;i++){ cnt[s[i] - '0']++; cntmod[(s[i] - '0') % 3]++; } for(int i = 9, j = n = 0; i >= 0; i--){ while(cnt[i]&&n<m){ int k = (i+j)%3; cnt[i]--, cntmod[i%3]--; if(!judge((3-k)%3, m-n-1)){ cnt[i]++, cntmod[i%3]++; break; } s[++n] = '0'+i, j = k; } } s[n+1] = '