P3800 수집 문제에 대한 해결책 [전원]

블로그에 대한 최초의 파렴치한 선전 \ (\ wwwwww)
기사 목록 - 핵융합 원자로 노심 - 루오 Gubo 오프


지식 : \ (민주당 \) 최적화, 모노톤 큐

  • 질문의 의미 :

    \ ((N \ 시간 M) \) 의 매트릭스 크기
    점의 부분 행렬 값과는
    출발점으로, 임의의 위치를 첫 번째 행을 선택할 수있다.

    현재 위치 들어 \ ((I, J) \\) (단면으로 도시 \ (I는 \)\ (J \) 열)
    로 전송 될 수있다 : \ ((I + 1, \ [JT, T + J를. ] \) \) 임의의 지점에 (\ (JT> 0 \
    \의 J + t \ leqslant M) \) 와 현재 위치의 위치 값이 획득된다.

    요구 사항 : 달성 할 수있는 최대 값과

    샘플 설명 :
    견본

    1. 성령에서 꿈 \ ((1,1) \) 출발 :의 총 가치 \ (+ 3 \)는 지금 \ (3 \)
    2. 영적 꿈에 이동 (\) (2,2) \ : 총 가치를 \ (3 + \)은 지금 \ (6 \)
    3. Reimu가 진행 \ ((3,3) \) : 합계 값 \ (3 + \) 지금 \ (9 \)
    따라서, 총 값 뿐만 \ (9 \)


  • 문제의 의미 분석 :

    분명히 이것은이다 \는 (DP \)의
    상태 천이 방정식은 매우 간단하다
    사용 \ ([I]은 [J f를 ] \) 포인트 나타내는 \을 ((나는 J) \ ) 의 최대 값에 도달 할 수
    있다 : \ (F [I] [J ] = 최대 (F [I-1] [K]) + V [I] [J] \에서 \ (케이 \ [JT, J + T] \) \)

    • 폭력 :
      모든 점 직접 열거하고 그 점을 열거 전송할 수?
      복잡성 \ (O (N ^ 3) \) 레벨
      \ (40 부 \)

    최적화를 고려 :

    • 실측치 :
      \ (I는 \) 행의 점 \ (F [] [] \) , 첫 번째 (\ I-1) \ 행 관련된
      수있는 각각의 두 인접 행 고려 중 각 스플릿 :

    도표 :

    슬라이딩 창

    그것은 찾을 수 있습니다 :
    1. 전송 포인트 \ ((I, J) \ ) 포인트
      위한 \ (I-1 \) 라인 간격 \ (\ 밑줄 {[JT, J + T]} \) 에서 \ (F [] [] \) 최대의 포인트

    2. 전송 포인트 \ ((I, J + 1 ) \) 포인트
      위한 \ (I-1 \) 라인 간격 \ (\ 밑줄 {[J = T + 1, J + T + 1]} \) 의 , \ (F [] [] \) 의 최대 점

    3. 전환점 ((I, J + 2) \) \ 점이
      된다 \ (I-1 \) 라인 간격 \ (\ 밑줄 {[J = T, T + J + 2 + 2]} \) 의 , \ (F [] [] \) 의 최대 점

    이 개 간격 이후
    에 통해 간격이 될 수 하나 개의 단위로 권리를 얻을
    이 우리가 다른 질문을 생각하게 P1886 슬라이딩 창
    , 당신은 단조로운 큐를 배운하지 않은 경우이 기사를 추천 :
    [로스 밸리 매일 # 9 ] [Sweetlemon] 꽃으로 OI 고등학교 팀은 투쟁 - 단조로운 큐에

    슬라이딩 윈도우 타입 최대 문제는
    물론, 모노톤 큐가 유지 될 수있다.

    위의에서, 우리는 적절한 발견 \ (DP \) 단조로운 큐 최적화 : 최적화.


  • 알고리즘 :

    하는 업데이트 이제 가정 (내가 \) \ 라인 :

    1. 모노톤 초기화 큐
      업데이트 할 수 \ ((I, 1) \ ) 포인트 \ ((I, K) (K \의 [1,1 + T]) \) ,
      첨가 모노톤 큐
    2. 주기, 업데이트 시작 \ ([1, M]을 \ ) 각 지점에서 :
      • 로 전송할 수 있습니다 \ (J \) 오른쪽 포인트 \ ((. 1-I, J + T) \) , 큐에
      • 단조 큐에 전달 될 수 실측치 (J \) \ 최대 점의 \을 (F [] [] \)
      • 최대로 \ (F [] [] \) 업데이트 \ (F [I] [J ] \)
    3. 모노톤 빈 큐 외층으로 순환 제 업데이트 \ (ⅰ + 1 \) 라인

    마지막으로, 최종 라인 찾아
    최대의 \ (F [N] [J] \) ,
    즉을 최고 값을 구한다.


코드에서 :

아날로그 어레이 필기 큐를 사용하기 때문에,
간단히 제 소자와 팀 헤드 및 테일 포인터를 비우는 재설정.
상수 비트 완화 \ (양단 큐의 \)를

#include<cstdio>
#include<ctype.h>
#include<cstring>
#define int long long
#define max(a,b) a>b?a:b
//=====================================
const int MARX = 4e3+10;
int n,m,k,t, now,ans;
int f[MARX][MARX];
int head=1,tail=1;//手写双端队列 
int q[MARX]={9223372036854775807};//为q[0]赋一个极大值,来防止插入元素时越界 
//=====================================
inline int read()
{
    int fl=1,w=0;char ch=getchar();
    while(!isdigit(ch) && ch!='-') ch=getchar();
    if(ch=='-') fl=-1;
    while(isdigit(ch)){w=w*10+ch-'0',ch=getchar();}
    return fl*w;
}
void in(int x)//向单调队列中插入元素 
{
    while(f[now-1][x]>f[now-1][q[tail]] && tail>=head) 
      tail--;//取出队尾小于插入元素的数 , 以保证单调性 
    q[++tail]=x;//插入队尾 
}
int find(int x)//查询元素 
{
    if(x+t<=m)in(x+t);//将能转移到x点 的 最后一个元素 x+t 插入队列 
    while(q[head]+t<x) head++;//找到队首第一个能够转移到x的点 
    return q[head]; 
}
//=====================================
signed main()
{
    n=read(),m=read(),k=read(),t=read();
    while(k--)
    {
      int x=read(),y=read(),w=read();
      f[x][y]=w;
    }
    
    for(now=2;now<=n;now++)//从第二行,开始转移 
    {
      for(int i=1;i<=t;i++) in(i);//初始化单调队列 , 满足能够 转移j=1的点 
      for(int j=1;j<=m;j++) f[now][j]+=f[now-1][find(j)];// 进行转移 
      head=tail=1 , q[1]=0;//清空队列 
    }
    
    for(int i=1;i<=m;i++)//取得最大值 
      ans=max(ans,f[n][i]);
    printf("%lld",ans);
}

문제이 완벽한 솔루션, 동양 공공 믿음 \ (+ \)

추천

출처www.cnblogs.com/luckyblock/p/11456237.html