#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);
}
}