【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;
}
posted @ 2017-10-04 18:44  AWCXV  阅读(217)  评论(0编辑  收藏  举报