题意:
现在有一个n*m的矩形,每条边都是一条路,每个1*1的矩形的正中央有一个数字。每次给你起始点(在边上)一个包含L,R,U,D的字符串,表示走的方向,最终你走的会是一个简单多边形。问你被多边形包含的所有数字有多少个不同的。
题解:
这道题有两个点:
1.首先是选择的算法,假设每次都是暴力地遍历所有在多边形内的点,每次最多的时间复杂度是n*m,然后对于字符串长度最少需求是2*n+2*m,那么4e6的字符串最多让我们遍历4e6/400/4=2500次整个矩形。也就是最大的时间复杂度是2500*400*400=4e8.正好
2.已经知道了是暴力,那么怎么找哪些点是被包含的,解法五花八门,但是有一种容易被人忽略并且非常简单的方法:
保存每列的所有出现的行,按照位置从小到大排序之后,矩阵中第i~i+1(i是奇数)的那些数是被包含的:
=>
红色的就是入边,蓝色的就是出边,每次只要枚举所有的行,然后再暴力枚举第i~i+1个边即可(注意边界条件,因为是将值保存到右下角,所以边也要算右下角的)
#include<bits/stdc++.h>
using namespace std;
const int N=405,M=2e6+5;
char s[M];
int mp[N][N];
bool vis[N*N];
vector<int>vec;
int a[N][N],top[N];
int main()
{
int t;
scanf("%d",&t);
while(t--){
int n,m,q;
scanf("%d%d%d",&n,&m,&q);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%d",&mp[i][j]);
while(q--){
int x,y;
scanf("%d%d%s",&x,&y,s);
for(int i=0;i<=n;i++)top[i]=0;
vec.clear();
int len=strlen(s);
for(int i=0;i<len;i++){
if(s[i]=='L')
x--,a[x+1][++top[x+1]]=y;
else if(s[i]=='R')
x++,a[x][++top[x]]=y;
else if(s[i]=='U')
y++;
else
y--;
}
int ans=0;
for(int i=1;i<=n;i++){
sort(a[i]+1,a[i]+1+top[i]);
for(int j=1;j<=top[i];j+=2)
for(int k=a[i][j]+1;k<=a[i][j+1];k++)
if(!vis[mp[i][k]])
ans++,vis[mp[i][k]]=1,vec.push_back(mp[i][k]);
}
printf("%d\n",ans);
for(int i:vec)
vis[i]=0;
}
}
return 0;
}