【BestCoder Round #93 1002】MG loves apple
【题目链接】:http://acm.hdu.edu.cn/showproblem.php?pid=6020
【题意】
给你一个长度为n的数字,然后让你删掉k个数字,问你有没有删数方案使得剩下的N-K个数字是3的倍数;
【题解】
这里我们枚举最后N-K个数字它的最高位是第几位;
这样我们就能在枚举最高位的时候直接判断这个数字是不是0;这样对合法性的处理就简单很多了;
我们枚举第i位是最高位,言外之意就是说前i-1个数字已经全部被删掉了;
则我们要在i+1..n这些数字里面再删掉k-i+1个数字才行;
这里设i+1..n这些数字的和对3的取余结果为rest
则
如果rest为1
我们先在i+1..n里面删掉1个取余结果为1的数字或者在i+1..n里面删掉2个取余结果为2的数字;后续的工作我们等下再说.
如果rest为2
我们先在i+1..n里面删掉1个取余结果为2的数字或者在i+1..n里面删掉2个取余结果为1的数字;
至此我们把问题转换成
在i+1..n里面删掉k-i+1-x个数字(x是我们刚才因为rest不等于0先假设删掉的数字)然后要求i+1..n所有的数字的和%3的结果为0;
这里我们只要考虑1+2和0两种形式了;
对于1+2类型的,我们只要考虑最多出现2组配对;
即两组1+2
因为如果你出现了3组1+2,其实也就是3个1和3个2了;
所以我们枚举出现了几组”1+2”类型->i然后i∈[0..2]
然后1剩下r1-i个,2剩下r2-i个,然后1能够选(r1-i)/3*3个,2能够选(r2-i)/3*3个;
之所以3个3个地选,是保证删除这些数字之后取余结果仍然保持0;
然后3个3个地选完之后,再看看余为0的个数有多少个;看够不够凑足k-i+1-x个数字;够的话就可行;
这里没办法考虑到删掉n-1个数字然后结果为0的情况;
所以要特判.
【完整代码】
#include <bits/stdc++.h>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define LL long long
#define rep1(i,a,b) for (int i = a;i <= b;i++)
#define rep2(i,a,b) for (int i = a;i >= b;i--)
#define mp make_pair
#define ps push_back
#define fi first
#define se second
#define rei(x) scanf("%d",&x)
#define rel(x) scanf("%lld",&x)
#define ref(x) scanf("%lf",&x)
typedef pair<int, int> pii;
typedef pair<LL, LL> pll;
const int dx[9] = { 0,1,-1,0,0,-1,-1,1,1 };
const int dy[9] = { 0,0,0,-1,1,-1,1,-1,1 };
const double pi = acos(-1.0);
const int N = 1e5+100;
int n, k;
char s[N];
int a[N],t[N],hzh[N][3];
bool ok(int r0, int r1, int r2, int k)
{
if (r0 < 0 || r1 < 0 || r2 < 0 || k < 0) return false;
if (k == 0) return true;
rep1(i, 0, 2)
{
if (r1 < i || r2 < i) break;
if (2 * i > k) break;
int restk = k - 2 * i;
if (restk == 0) return true;
int d = (r1 - i) / 3 * 3 + (r2 - i) / 3 * 3;
if (d < restk)
{
if (d + r0 >= restk) return true;
}
else//d>=restk
{
restk %= 3;
if (r0 >= restk)
return true;
}
}
return false;
}
int main()
{
//freopen("F:\\rush.txt", "r", stdin);
int T;
rei(T);
while (T--)
{
rei(n), rei(k);
scanf("%s", s + 1);
rep1(i, 1, n)
{
a[i] = s[i] - '0';
t[i] = a[i] % 3;
}
rep1(i, 0, 2) hzh[n + 1][i] = 0;
rep2(i, n, 1)
{
rep1(j, 0, 2) hzh[i][j] = hzh[i + 1][j];
hzh[i][t[i]]++;
}
int rest = (hzh[1][1] + hzh[1][2] * 2) % 3;
bool fi = false;
rep1(i, 1, n)
{
if (a[i] > 0)
{
if (rest == 0 && ok(hzh[i + 1][0], hzh[i + 1][1], hzh[i + 1][2], k - i + 1)) {
fi = true; break;
}
if (rest == 1 && (ok(hzh[i+1][0],hzh[i+1][1]-1,hzh[i+1][2],k-i)||ok(hzh[i+1][0],hzh[i+1][1],hzh[i+1][2]-2,k-i-1))) {
fi = true; break;
}
if (rest == 2 && (ok(hzh[i + 1][0], hzh[i + 1][1] - 2, hzh[i + 1][2], k - i-1) || ok(hzh[i + 1][0], hzh[i + 1][1], hzh[i + 1][2] - 1, k - i))) {
fi = true; break;
}
}
rest = (rest - t[i] + 3) % 3;
}
if (k == n - 1 && hzh[1][0] > 0) fi = true;
if (fi) puts("yes"); else puts("no");
}
//printf("\n%.2lf sec \n", (double)clock() / CLOCKS_PER_SEC);
return 0;
}