【bzoj1028】[JSOI2007]麻将

首先枚举等待牌,再枚举对子牌。
 
然后1~n扫一遍,如果现在 s[i]不能被3整除,那么必须跟后两个数搭配几下变成能被3整除的。然后如果能被3整除,那么只要三个连续的一组可行,则三个相同的一组必定也可行。因为如果有一种方案是3个连续的而最小数又能被3整除,那这种就必须有3n组,3n组的话三个相同的为一组的方案也就存在了。
 
所以方法就是,n^2枚举等待牌和对子牌,o(n)扫描。扫描方法是,从1~n来做,如果s[i]不能整除三就消掉几个让他能整除三,然后就三个为一组的消去。
 
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<ctime>
using namespace std;
 
#define MAXN 410
 
int s[MAXN],c[MAXN],f[MAXN];
int n,m;
int k,w;
 
bool flag;
 
int work()
{
    bool ask;
    for (int i=1;i<=n;i++)
        if (s[i]>=2)
        {
            ask=1;
            s[i]-=2;
            for (int j=1;j<=n+2;j++)
                f[j]=s[j];
            for (int j=1;j<=n+2;j++)
            {
                if (f[j]<0)
                {
                    ask=0;
                    break;
                }
                f[j]%=3;
                f[j+1]-=f[j];
                f[j+2]-=f[j];
            }
            s[i]+=2;
            if (ask)
                return true;
        }
    return false;
}
 
int main()
{
    scanf("%d%d",&n,&m);
    for (int i=1;i<=3*m+1;i++)
    {
        scanf("%d",&k);
        s[k]++;
    }
    for (int i=1;i<=n;i++)
    {
        s[i]++;
        if (work())
        {
            flag=1;
            c[++c[0]]=i;
        }
        s[i]--;
    }
    for (int i=1;i<=c[0];i++)
    {
        printf("%d",c[i]);
        if (i!=c[0])
            printf(" ");
    }
    if (!flag)
        printf("NO");
    return 0;
}

  

posted @ 2016-03-25 20:58  Yangjiyuan  阅读(289)  评论(0编辑  收藏  举报