[CodeForces][단조로운 대기열 최적화 DP] 939F Cutlet
17735 단어 #CodeForcesDP단조 대기열 및 경사율 최적화
CodeForces 939F Cutlet
제목의 대의.
스테이크 한 조각은 양면 모두 N N N 초간 구워야 하는데, 지금은 K K 시간대 [L i, R i] [L i, R i] [Li, Ri]만 면을 뒤집을 수 있고, 이 시간 안에 이 스테이크를 마음대로 뒤집을 수 있다.
최소한 몇 번을 뒤집어서 스테이크 양쪽을 N, N, N 초간 구웠냐고.
분석하다.
신기한 DP.
정의 상태 f (i, j) f (i, j) f (i, j) 는 이전 i i 시간 동안 현재 위로 향하는 면이 j j 초의 최소 회전 횟수로 구워졌다.
상태 전환 방정식을 나열하는 것은 어렵지 않습니다.
분명히 이 이동은 O (N 2 K) O (N ^2 K) O (N 2 K) 이다.우리는 최적화를 고려해야 한다
결론: 우리가 한 구간에서 스테이크를 최대 두 번 뒤집을 때.
증명: 우리가 한 구간에서 세 번 이상의 스테이크를 뒤집을 때 우리는 단지 두 시간 간격으로 구운 스테이크의 면이 같다는 것을 발견할 수 있다. 그래서 우리는 등가의 교환 구간을 통해 스테이크의 뒤집는 횟수를 줄일 수 있다.
우리가 스테이크를 두 번 뒤집는 것은 다른 한 면만 한동안 구우기 위해서이며, 나올 때는 여전히 시작할 때의 한 면이다.이런 조작이 필요하다는 것을 증명할 수 있다.
우리가 한 번만 뒤집을 때 뒤집힌 후 양쪽에서 굽는 시간의 차이는 kk이고 뒤집는 시간은 jjj이다. 뒤집힌 후 위로 향하는 쪽의 굽는 시간은 Ri-3-jR 이다.i-j Ri -3. j, 아래 쪽으로 굽는 시간이 바로 R i -3. j -3. k Ri - j - k Ri−j−k.
뒤집으면 양면이 서로 바뀌기 때문에 f(i, j) = min {f(i-3, R i -3 j -3)} + 1 f(i, j) =\min\{f(i-1, R i -j-k)} + 1 f(i, j) = min {f(i -1, Ri -3 k)} +1이 있다.
의사결정의 단조성을 발견하기 어렵지 않기 때문에 단조로운 대열을 이용하여 의사결정점을 유지한다.
j+kj+kj+k를 직접 매거하는 것을 고려한 결과 이 이동은 거꾸로 매거해야 한다는 것을 발견했다.
우리가 두 번 뒤집었을 때 양면으로 굽는 시간 차이를 kk로 설정했는데 두 번 뒤집은 후에도 이 면이 아래로 향하기 때문에 f(i, j)=min{f(i-1, j-k)}+2f(i, j-k)}=\min\f(i-1, j-k)\}+2f(i, j)=min{f(i, j)=min{f(i-1, j-k)+2}를 얻었다.
마찬가지로 단조로운 대열로 유지할 수 있지만, 이 이동은 일일이 열거해야 한다.
그러므로 전체 시간의 복잡도는 O(NK)O(NK)O(NK)이다.
그리고 공간이 터지지 않도록 스크롤 그룹을 열었습니다.
참조 코드
#include
#include
#include
using namespace std;
const int Maxn = 200000;
const int Maxk = 100;
const int INF = 0x3f3f3f3f;
int N, K;
int L[Maxk + 5], R[Maxk + 5];
int f[2][Maxn + 5];
int q[Maxn + 5];
int main() {
#ifdef LOACL
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
scanf("%d %d", &N, &K);
for(int i = 1; i <= K; i++)
scanf("%d %d", &L[i], &R[i]);
memset(f[0], 0x3f, sizeof f[0]);
f[0][0] = 0;
int z = 1;
for(int k = 1; k <= K; k++) {
memcpy(f[z], f[z ^ 1], sizeof f[z]);
int head = 1, tail = 0;
for(int i = 0; i <= min(N, R[k]); i++) {
while(head <= tail && f[z ^ 1][i] <= f[z ^ 1][q[tail]])
tail--;
q[++tail] = i;
while(head <= tail && q[head] < i - (R[k] - L[k]))
head++;
f[z][i] = min(f[z][i], f[z ^ 1][q[head]] + 2);
}
head = 1, tail = 0;
for(int i = R[k]; i >= 0; i--) {
while(head <= tail && f[z ^ 1][R[k] - i] <= f[z ^ 1][q[tail]])
tail--;
q[++tail] = R[k] - i;
while(head <= tail && q[head] < L[k] - i)
head++;
f[z][i] = min(f[z][i], f[z ^ 1][q[head]] + 1);
}
z ^= 1;
}
if(f[z ^ 1][N] >= INF) puts("Hungry");
else printf("Full
%d
", f[z ^ 1][N]);
return 0;
}
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Rails Turbolinks를 페이지 단위로 비활성화하는 방법원래 Turobolinks란? Turbolinks는 링크를 생성하는 요소인 a 요소의 클릭을 후크로 하고, 이동한 페이지를 Ajax에서 가져옵니다. 그 후, 취득 페이지의 데이터가 천이 전의 페이지와 동일한 것이 있...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.