Puzzle
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 383 Accepted Submission(s): 208
Problem Description
A Jigsaw puzzle contains N*M-1 pieces of jigsaws in a N rows*M columns rectangular board.Each jigsaw has a distinct number from 1 to N*M-1.Li is a naughty boy,he wants to arrange the board in his unique way.At the beginning,he picks all N*M-1 jigsaws out and put them on the table and then he will put them back to the board respecting the following steps:
1.Sorting all the remaining jigsaws on the table in ascending order.
2.Picking out the 1st ,the P+1 th ,the 2*P+1 th,......the n*P+1 th jigsaws and put them back to the blank area in the board one by one from the top row to the bottom row,from the left column to the right column.
3.if there are jigsaws remained on the table,back to step 1.
After he arranging the board,it’s obvious that there’s only one blank area located at the bottom-right corner.
Your task is to make the numbers on jigsaws sorted with every row and every column in ascending order(From left to right,top to bottom),and the blank area should be located at the bottom-right corner in the end.Each step you can move the blank area’s neighboring jigsaws(which share a common side with the blank area) towards the blank area.It’s really a difficult question,so you need to write a program to judge whether it is possible to complete the task.
1.Sorting all the remaining jigsaws on the table in ascending order.
2.Picking out the 1st ,the P+1 th ,the 2*P+1 th,......the n*P+1 th jigsaws and put them back to the blank area in the board one by one from the top row to the bottom row,from the left column to the right column.
3.if there are jigsaws remained on the table,back to step 1.
After he arranging the board,it’s obvious that there’s only one blank area located at the bottom-right corner.
Your task is to make the numbers on jigsaws sorted with every row and every column in ascending order(From left to right,top to bottom),and the blank area should be located at the bottom-right corner in the end.Each step you can move the blank area’s neighboring jigsaws(which share a common side with the blank area) towards the blank area.It’s really a difficult question,so you need to write a program to judge whether it is possible to complete the task.
![](https://i-blog.csdnimg.cn/blog_migrate/2bcd99a6d975cce04cd8597a46f5e90c.jpeg)
![](https://i-blog.csdnimg.cn/blog_migrate/4dbefccc5978b94277fb54c3eaab852b.jpeg)
Input
The first line contains an integer T(T<=100),which represents the number of test cases.
Following T lines,each line contains three integers N,M,P(2<=N,M<=1000;1<=P<=N*M-2).
Following T lines,each line contains three integers N,M,P(2<=N,M<=1000;1<=P<=N*M-2).
Output
For each test case,print “YES” in a separate line if it is possible to complete the task ,otherwise please print “NO”.
Sample Input
3 3 2 3 3 2 4 999 999 1
Sample Output
YES NO YES
//题意:N*M的拼图,最右下角的那格是空的,每次可以把一个和空格有公共边的块和空格交换,一开始以“Picking out the 1st ,the P+1 th ,the 2*P+1 th,......the n*P+1 th jigsaws and put them back to the blank area in the board one by one from the top row to the bottom row,from the left column to the right column.”这个方式打乱,问能通过移动把拼图变为1-(n-1)有序的吗。
//思路:根据官方题解,一开始无论按什么顺序放都可以通过移动变成一下这种形式:
以5*4为例
1 2 3 4 5
6 7 8 9 10
11 12 13 * *
16 17 18 *
*表示不能确定
也就是说只有最后2*2的矩形里的值不能确定。
枚举2*2的6中情况,发现相同逆序对奇偶性的局面可以互相到达(逆序对数指每个数后面比这个数小的数的个数)。
1 2 2 3 3 1
3 1 2
1 3 2 1 3 2
2 3 1
上面三种逆序对数是偶数,可以互相到达;下面三种逆序对数是奇数,也可以互相到达。但显然,前三种可以得到最后我们想要的局面而后三种不行。
所以只要考虑一开始数列(从左往右,从上到下,把拼图里的数的值组成的数列)的逆序对数,如果是偶数,输出"YES",奇数输出“NO”。
还要找下规律,能发现逆序对数的贡献成等差数列。公差是p-1,项的个数为(num-1)/p+1,其中num为N*M-1。
举个例子:
以4*4 p=2为例
1 3 5 7 9 11 13 15...
第一次开始的几个数这样的,可以看出后面的书里比3小的是在1-3中间的几个,即p-1个,而比5小的是1-3,3-5之间的几个,即2*(p-1)个,以此类推......,在每次里总共有(num-1)/p+1个,所以每次最后是((num-1)/p)*(p-1)。
每次等差数列求和即可。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <algorithm>
using namespace std;
int main()
{
int T;
int n, m, p;
scanf("%d", &T);
while (T--)
{
scanf("%d%d%d", &n, &m, &p);
int num = n*m - 1;
int tot = 0;
//这里必须是num>p
//因为p可以取到1e6 -1,所以如果是num>0要多处理1e6 -1个循环,会TLE
while (num > p)
{
int sum = (num - 1) / p + 1;
tot += (sum - 1)*sum*(p - 1) / 2;
num -= sum;
}
if (tot % 2 == 0)
printf("YES\n");
else
printf("NO\n");
}
return 0;
}