INPUT
6
3
3 6 9
1 4 7
3
3 6 9
1 3 8
5
1 2 3 4 5
6 7 8 9 10
10
1 1 1 1 1 1 1 1 1 1
2 3 2 3 2 3 2 3 2 3
2
3 1
2 3
2
3 1
1 2
output
YES
NO
YES
YES
YES
NO
题意:给出2*n个数,任意排列成2行n列,问有没有一种方法可以使得任意相邻的两个相加不能被3整除。
思路:按照求余3的值分类,求余为0的x个,求余为1的y个,求余为2的有z个。当x>n一定是不能组成的。然后根据x的个数来区分。原则是任意两个求余为0的不能放在一起,一个求余为1和求余为2的不能放一起。
1.当x==0时,剩余的必须全是y或者全是z.
2.当x==1时,yz必须有一个为0,一个不为0.
3.当x==2时,必须错开并且起到分界线的作用。
4.当x==3时,将x个数按照波浪线放置,那么会有x-2个任意放置的。可以遍历y个数放置,使得剩余左边和右边的区域都是同一种的。
具体请看代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<vector>
#include<algorithm>
#include<map>
using namespace std;
#define inf 0x3f3f3f3f
const int mod=1e4+10;
const int M=1e4+10;
int main()
{
// freopen("//home//acm//桌面//in","r",stdin);
int T,n,p,flag;
scanf("%d",&T);
while(T--)
{
flag=0;
scanf("%d",&n);
int x=0,y=0,z=0;
for(int i=0; i<2*n; i++)
{
scanf("%d",&p);
if(p%3==0)
x++;
else if(p%3==1)
y++;
else
z++;
}
if(x > n)
flag=0;
else
{
if(x >= 3)
{
if(y == 0 || z == 0)
flag=1;
else
{
for(int i=1; i<=y; i++)
{
int p = x - 2 -i;
int tmp1 = y - i;
int tmp2 = z - p;
if(tmp1%2 == 1 && tmp2%2 == 1 || tmp1 == 0 || tmp2 == 0)
{
flag=1;
break;
}
}
}
}
else if(x == 2)
{
if(y%2 == 1 && z % 2 == 1 || y==0 || z==0)
flag=1;
}
else if(x == 1)
{
if(y==0 && z!=0 || y!=0 && z==0)
flag=1;
}
else if(x == 0)
{
if(y == 2*n || z == 2*n)
flag=1;
}
}
if(flag)
printf("YES\n");
else
printf("NO\n");
}
return 0;
}