Processing math: 100%

1716

Aug 09, 22

Editorial


C

문제 요약:

2*n 격자판이 있는데, 로봇은 처음 (1,1)에 있고, 상하좌우 1칸으로만 움직이고, 밖으로 나갈 수 없다.

중복 없이 모든 칸을 방문해야 하는데, 칸에 적힌 숫자만큼 시간이 돼야 칸이 열린다.

몇초만에 다 방문할 수 있는가?

문제 해설:

어떤 칸(i,j)(0-indexed)에서

,,,, 식으로 빈 칸 없이 채우며 맨 끝까지 가는 것을 snake,

맨 끝(i,n1)까지 갔다가 (1i,n1)을 거쳐 밑(1i,j)으로 돌아오는 것을 hook라고 하자.

중간에 방문하지 않은 칸이 존재하면 안 되므로, snake를 하면서 중간에 hook를 하는 것들 중에 답이 있을 것이다.

hook를 빨리 하기 위해 미리 (i,j)칸에서 hook을 시작하기 위한 시간을 계산하는 배열 d를 미리 계산한다.

di,j=(i,j)칸에서 시작해서 끝까지 갔다가 (1i,j)칸으로 돌아올 때 기다리는 칸이 없게 가장 빨리 출발할 수 있는 시간이라고 하면,

di,j=max(di,j+11 ,ai,j ,a1i,j (2(nj)1))이다.

di,j+1은 오른쪽 한 칸 뒤(i,j+1)에서 hook할 때의 값을 나타내므로, 앞에 한 칸(i,j)이 생기므로 1초 빨리 출발하는 것과 마찬가지 이므로 di,j+11과,

ai,j는 지금 칸,

a1i,j는 지금 칸의 위/아래 칸인데, 끝까지 갔다가 (nj1) 밑으로 내려가고 (1), 또 돌아오면 (nj1) 이므로 모두 합하면 a1i,j (2(nj)1)이 된다.

따라서 hook을 하기 위한 계산을 하고,

snake를 하는 것을 반복해 가면서 멈춘 칸에서 hook을 하는 경우를 계산하고, 최솟값에 2n1(이동 거리)를 더하면 답이 된다.

의견: 이렇게 해도 되는데, 어떤 시간을 기준으로 되고 안 되고가 구분되므로 이분 탐색으로 했어도 가능했다는 사실을 알았다.


D

summary:

0에서 시작해서, k의 배수만큼 더하고, 그 다음엔 k+1,k+2, 만큼 더해 나간다.

1~n까지 각각의 수들에 도달하는 경우의 수를 세는 문제이다.

solution:

당연히 dp이고,

d(s,i)=si 라고 할 때

d(s,i)=jd(s1,ij(k+s1))이라고 할 수 있다.

그런데 i는 s(2k+s1)2를 넘을 수 없으므로(각 연산마다 더해야 하는 최소의 k가 존재하므로)

계산하는 전체 시간 복잡도는 O(nn)이 된다.

그런데 상태를 전부 저장하면 메모리 가 부족하다.

d(s,i)를 구하려면 이전 상태만 보면 되므로 d배열을 1차원으로 유지해서 계산하고 갱신하고를 반복해서 구한다.

더 자세하게는 d(s,i)=d(s1,ik)+d(s1,i2k)+d(s1,i3k)+이고 (k=현재 k의 값),

ik,i2k,i3k,들을 k로 나눈 나머지는 모두 같다.

따라서 현재 인덱스를 i라고 할 때, sum[i 이전의 수들을 k로 나눈 나머지]에 d[i 이전의 수] (이전 스텝의 것으로 생각)들을 모두 더하고

ans에 d[i]를 매번 더해주면 된다.

for (int mn = 0; mn+k<= n; mn += k++) {
    vl sum(n + 1);
    for (int i = mn; i <= n; i++) {
        int t = d[i];
        d[i] = sum[i % k]; //자기 이전까지
        (sum[i % k] +=t) %= mod;
        (ans[i] +=d[i]) %= mod;
        
    }
}

opinion:

실제로 생각했어야 하는 것은 메모리 문제를 어떻게 해결할지인데 시간 초과가 난다고 생각했다.