【思维·模拟】jzoj1433数码问题 纪中集训提高B组
Description
Alice有一个N*N的格子,把1-N^2按照从上到下从左到右的顺序填进表格中,允许在表格上进行两种操作:
(1) 旋转行——这一行的数向右移动一个位置,而最后一列的数会移到第一列;
(2) 旋转列——这一列的数向下移动一个位置,最后一行的数会移到第一行。
Alice想把数X移到(R,C)处可以采用以下方法:
•如果X不在C这一列,通过旋转行操作把X移到C这一列;
•如果X不在R这一行,通过旋转列操作把X移到R这一行。
下面是一个把6移到(3,4)的例子:
Alice现在想采用上述方法,依次把K个数移到各自的目标位置,编程计算每个数需要几次操作。
Input
第一行包含两个整数N(12<=N<=10000)和K(1<=K<=1000)。
接下来K行,每行包含三个整数X(1<=X<=N^2)、R和C(1<=R,C<=N),描述需要移动的数以及目标位置。
Alice必须按照输入顺序依次移动。
Output
输出K行,每行输出一个整数,表示操作次数。
Sample Input
输入1:
4 1
6 3 4
输入2:
4 2
6 3 4
6 2 2
输入3:
5 3
1 2 2
2 2 2
12 5 5
Sample Output
输出1:
3
输出2:
3
5
输出3:
2
5
3
考场上唯一A了的题,但还是想写一写,挺有意思的。
刚开始看错了题面以为询问之间相互独立 (那这不是大水题吗)
认真读了题目发现不是2333。
整个数组完全模拟肯定是不可能的,而且
n
n
n那么大。
发现
k
k
k比较小,于是将询问离线,只存需要被询问的点的位置更新状况,每一次操作都看一下后面的点再经过操作之后跑到哪里去了,更新它的位置,复杂度
k
2
k^2
k2,但其实还跑不满。
后面又在想如果没有规定先移行还是先移列的问题,那么移行移列的顺序是会影响答案的,那如果把这道题改成不限制先移什么,然后求最小的移动次数呢?
唔,好像有点难。(反正本蒟蒻没有思考出来)
#pragma GCC optimize(2)
//shu_ma_wen_ti
/*
每进行一次旋转行操作->列++
每进行一次旋转列操作->行++
先移列再移行
最少?
*/
#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;
#define MAXK 1005
#define LL long long
int n,k;
struct node{
int x,y,r,c;
}nd[MAXK];
inline int rd()
{
int f=1,x=0;char c=getchar();
while(c<'0'||'9'<c){if(c=='-')f=-1;c=getchar();}
while('0'<=c&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return f*x;
}
int main()
{
n=rd(),k=rd();
for(register int i=1;i<=k;i++)
{
int num=rd();nd[i].r=rd(),nd[i].c=rd();
nd[i].x=num/n,nd[i].y=num%n;
if(nd[i].y) nd[i].x++;
if(nd[i].y==0) nd[i].y=n;
}
for(register int i=1;i<=k;i++)
{
int move1=0,move2=0,ans=0;
if(nd[i].c>=nd[i].y) move2=nd[i].c-nd[i].y,ans+=move2;
else if(nd[i].c<nd[i].y) move2=n-nd[i].y+nd[i].c,ans+=move2;
if(nd[i].r>=nd[i].x) move1=nd[i].r-nd[i].x,ans+=move1;
else if(nd[i].r<nd[i].x) move1=n-nd[i].x+nd[i].r,ans+=move1;
printf("%d\n",ans);
for(register int j=i+1;j<=k;j++)
{
if(nd[j].x==nd[i].x)nd[j].y=(nd[j].y+move2+n-1)%n+1;
if(nd[j].y==nd[i].c)nd[j].x=(nd[j].x+move1+n-1)%n+1;
//printf("*%d %d %d\n",j,nd[j].x,nd[j].y);
}
}
return 0;
}