hihocoder#1573 : 小Hi与矩阵

#1573 : 小Hi与矩阵

时间限制:10000ms

单点时限:1000ms

内存限制:256MB

描述

小Hi有一天心血来潮想要玩数字游戏,于是他创造了一个新的游戏形式来刁难小Ho。给定一个N×N的矩阵,每个格子上有一个数字X,小Hi想要询问小Ho对于某一个格子(i,j),与该点的曼哈顿距离小于等于K的格子中一共有多少个数字可以整除K。

输入

第一行一个正整数N。 接下来N行,每行N个正整数,表示这个矩阵。

接下来一个正整数Q,表示Q次询问。

接下来Q行,每行有三个正整数i, j, K。

对于30%的数据,1 <= Q <= 100

对于100%的数据,1 <= Q <= 100000, 1<=X<=20, 1<=i, j<=N, 1<= N, K<=200

输出

对于每一个询问,输出一个整数表示答案。

样例输入

5
1 2 1 2 1
2 1 2 1 2
1 2 1 2 1
2 1 2 1 2
1 2 1 2 1
5
3 3 2
3 3 1
5 5 2
3 2 5
2 1 2

样例输出

13
1
6
13
8

EmacsNormalVim

 GCC G++ C# Java Python2 

 

题解:

观察每一次询问

–本质上是询问一个菱形中满足性质的数量

–菱形不方便分解

我们不妨将其旋转45度,成为一个正方形

而正方形就可以分解了

至于旋转,具体来说就是 (i,j)(i+j-1,n-i+j)

然后变成了一个(n*2-1)*(n*2-1)的矩阵,每两个元素之间都有一个空。

然后就可以愉快的搞了。把读进来的坐标转化之后求出控制范围的矩阵中的和即可。

代码:

#include<bits/stdc++.h>
using namespace std;
int n,g[21][401][401],a[201][201],ans;
int check(int now,int x,int y){
	x=max(x,0);x=min(x,n*2-1);
	y=max(y,0);y=min(y,n*2-1);
	return g[now][x][y];
}
int solve(int now,int xl,int yl,int xr,int yr){
	return check(now,xr,yr)-check(now,xl-1,yr)-check(now,xr,yl-1)+check(now,xl-1,yl-1);
}
int main(){
	int i,j,t,k,s,x,y,ii,Q;
	scanf("%d",&n);
	for(i=1;i<=n;i++)
	 for(j=1;j<=n;j++)scanf("%d",&a[i][j]);
	for(ii=1;ii<=20;ii++){
		for(i=1;i<=n;i++){
			for(j=1;j<=n;j++){
			 if(a[i][j]==ii)g[ii][i+j-1][n-i+j]=1;
//			 printf("%d %d %d %d %d\n",ii,i,j,a[i][j],g[ii][i+j-1][n-i+j]);
		}
		}
		for(i=1;i<=n*2-1;i++)
		 for(j=1;j<=n*2-1;j++)g[ii][i][j]+=g[ii][i-1][j]+g[ii][i][j-1]-g[ii][i-1][j-1];
	}
/*	for(i=1;i<=n*2-1;i++){
	 for(j=1;j<=n*2-1;j++){
	 	printf("%d ",g[1][i][j]);
	 }
	 puts("");
}*/
	scanf("%d",&Q);
	while(Q--){
		scanf("%d%d%d",&t,&k,&s);
		x=t+k-1;y=n-t+k;
	//	printf("%d %d\n",x,y);
		ans=0;
		for(i=1;i<=20;i++)
		 if(s%i==0)ans+=solve(i,x-s,y-s,x+s,y+s);
		printf("%d\n",ans); 
	}
}

猜你喜欢

转载自blog.csdn.net/qq_41510496/article/details/81093284
Hi~
hi