zoukankan      html  css  js  c++  java
  • 【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("
    %.2lf sec 
    ", (double)clock() / CLOCKS_PER_SEC);
        return 0;
    }
  • 相关阅读:
    创建线程的方式三:实现Callable接口 --- JDK 5.0新增
    线程的通信
    多线程的实例练习:银行账户双储户问题
    解决线程安全问题的方式三:Lock锁 --- JDK5.0新增
    演示线程的死锁问题
    Synchronized的各场景使用方法(多窗口售票例子接上篇)
    线程的【生命周期】和【线程的同步】(下面有多窗口售票例子)
    多线程:继承方式和实现方式的联系与区别
    创建多线程的方式二:实现Runnable接口
    Java项目生成可执行jar包、exe文件以及在Windows下的安装文件
  • 原文地址:https://www.cnblogs.com/AWCXV/p/7626489.html
Copyright © 2011-2022 走看看