[NOIP2017 A팀 시뮬레이션 7.14 향상] 긴급 철수.
n*m의 0,1 행렬(1<=n, m<=500)을 제시하고 한 점에서 출발하여 매번 아래로 또는 오른쪽으로만 갈 수 있고 1로 갈 수 없는 규칙을 규정한다. 여러 그룹은 (1<=Q<=600000)을 묻고 한 점에서 다른 점으로 갈 수 있는지 묻는다.
문제 풀이:
이 문제는 질이 매우 높다.이것은 오프라인으로 만든 것이라고 생각하기 쉽다.우리는 대열을 나누어 치료할 수 있다.현재 물어볼 열이 [x.y] 구간에 있다고 가정하고 m=(x+y)/2를 설정하고 m열을 연결열로 합니다.fi, j, S를 설정하면 (i, j) 이 점이 중간열에 들어갈 수 있는 S를 나타낸다. S는 하나의 점집이다. 이 물건은 직접 dp로 할 수 있고 S는bitset으로 신속하게 해결할 수 있다.그리고 매거 질문을 해서 중간열을 통과했는지 확인한다. 통과했다면 두 점의 S가 교차했는지 직접 볼 수 있고 만약에 한 점이 m열에서 특판해야 한다.이어서 [x.m-1], [m+1.y]를 치료한다.물론 문의는 미리 순서를 정해야 한다. 그렇지 않으면 매번 폭발할 때마다 반드시 시간을 초과한다.시간 복잡도: O(n ∗ m∗ log m∗ n32)
Code:
#include
#include
#include
#include
#define fo(i, x, y) for(int i = x; i <= y; i ++)
#define fd(i, x, y) for(int i = x; i >= y; i --)
using namespace std;
const int N = 505, Q = 600005;
int n, m, q, p[N][N], ans[Q];
int cur[N][N], final[N][N], tot;
struct edge {
int c, d, next, e;
}e[Q];
struct node {
int a, b, c, d, e;
}d[Q];
bitset<505> f[501][501], emp;
bool rank(node a, node b) {
return a.d < b.d;
}
void link(int a, int b, int c, int d, int ee) {
e[++ tot].next = final[a][b], e[tot].c = c, e[tot].d = d, e[tot].e = ee, final[a][b] = tot;
}
void Init() {
scanf("%d %d", &n, &m);
fo(i, 1, n) {
fo(j, 1, m) {
char ch = ' '; for(;ch != '0' && ch != '1'; ch = getchar());
p[i][j] = ch - '0';
}
}
scanf("%d", &q);
fo(i, 1, q) scanf("%d %d %d %d", &d[i].a, &d[i].b, &d[i].c, &d[i].d), d[i].e = i;
sort(d + 1, d + q + 1, rank);
fo(i, 1, q) link(d[i].a, d[i].b, d[i].c, d[i].d, d[i].e);
}
void dg(int x, int y) {
if(x > y) return;
int m = (x + y) / 2;
fd(j, m, x) fd(i, n, 1) {
f[i][j] = emp;
if(p[i][j]) continue;
if(j == m) f[i][j][i] = 1;
if(j != m) f[i][j] |= f[i][j + 1];
if(i != n) f[i][j] |= f[i + 1][j];
}
fo(j, m, y) fo(i, 1, n) {
f[i][j] = emp;
if(p[i][j]) continue;
if(j == m) f[i][j][i] = 1;
if(j != m) f[i][j] |= f[i][j - 1];
if(i != 1) f[i][j] |= f[i - 1][j];
}
fo(j, x, m) fo(i, 1, n) {
for(int k = cur[i][j]; k; k = e[k].next, cur[i][j] = k) {
int c = e[k].c, d = e[k].d, cc = e[k].e;
if(d < m) break;
if(j == m && d != m) {
ans[cc] = f[c][d][i];
continue;
}
if(d == m && j != m) {
ans[cc] = f[i][j][c];
continue;
}
ans[cc] = (f[i][j] & f[c][d]).any();
}
}
dg(x, m - 1); dg(m + 1, y);
}
void Mid() {
fo(i, 1, n) fo(j, 1, m) cur[i][j] = final[i][j];
dg(1, m);
}
void End() {
fo(i, 1, q) if(ans[i]) printf("Safe
"); else printf("Dangerous
");
}
int main() {
Init();
Mid();
End();
}
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
귀속(분치)분치(divide and conquer): 원래의 문제를 규모가 비교적 작은 구조와 원문제가 같거나 비슷한 자문제로 나누어 각각 이 자문제를 해결하고 마지막에 자문제를 합쳐서 원문제의 해를 얻는다. 1. n = 3 ...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.