【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; }