간격 \ (DP \) 검토를 강화하기
나는이 파 문제는 정말 간단하다 말해야한다. . .
기술 요약 :
1. 때로는 전송하고 피곤해 배낭 사용할 수 있습니다
2. 표제를 제한하는 제한을 추가 할 수있는 유사한 부분 직접 시간 고려 구간에 발생 될 수 발생할 경우 \가 ([L, R] \ )가 된다 \을 ([내가 J] \ ) 상황이 완전히 포함
[BZOJ4897] 목 여름 Camp2016] 대본
배낭 전송의 전형적인 사용 \ (DP [I] [J]를 \) 이 처리 나타낸다 \ ([난, j]가 \ )은 섹션 답
전이 기간 간격으로 배치 될 수 있거나 때 직접 제 프로세스에서 완료 ([I] [J DP \를 ] \) 인수에, 이것은 배낭 유지할 수
const int N=52,P=999983,INF=1e9;
int n,a,b,w[N];
int dp[N][N];
int tmp[N][N][N];
int id[N*N];
inline void cmin(int &a,int b){ ((a>b)&&(a=b)); }
inline void cmax(int &a,int b){ ((a<b)&&(a=b)); }
int main(){
n=rd(),a=rd(),b=rd();
w[0]=0,w[n+1]=1001;
rep(i,1,n) w[i]=rd();
rep(i,0,n+1) id[w[i]]=i;
memset(dp,63,sizeof dp);
rep(i,1,n) {
int ma=0,mi=INF;
rep(j,i,n) {
ma=max(ma,w[j]),mi=min(mi,w[j]);
dp[i][j]=(ma-mi)*(ma-mi)*b+a;
}
}
drep(i,n,1) {
memset(tmp,63,sizeof tmp);
tmp[i-1][n+1][0]=0;
rep(j,i,n) {
drep(k,j,i) {
rep(a,0,n+1) {
rep(b,0,n+1) {
cmin(tmp[j][a][b],tmp[k-1][a][b]+dp[k][j]);
}
}
}
rep(a,0,n+1) {
rep(b,0,n+1) if(tmp[j-1][a][b]<INF) {
cmin(tmp[j][id[min(w[a],w[j])]][id[max(w[b],w[j])]],tmp[j-1][a][b]);
}
}
rep(a,1,n) {
rep(b,1,n) if(tmp[j][a][b]<INF) {
cmin(dp[i][j],tmp[j][a][b]+(::a)+::b*(w[b]-w[a])*(w[b]-w[a]));
}
}
}
}
printf("%d\n",dp[1][n]);
}
\ [\ \]
\ [\ \]
[BZOJ4350] 돼지 남자 시퀀스 전투 브래킷
전송 시간 제한을 고려 \을 (DP \)
첫째로,이 문제는 스택 중 문제로 변형 될 수 있으며, 스택은 한계가있다
\ (DP [I] [J ] \) , 즉 \ (I는 \) 하기 (J \) \ 세그먼트의 포인트 수를 펑되는 프로그램 부
그런 다음 우리는 이동 \ (DP [내가] [j는 ] \) 때 스택에서 마지막을 열거 할 (케이 \) \ (너무 술병의 숫자하지 않음) 제한의 준수를 확인하기를,
template <class T> inline void cmax(T &a,T b){ ((a<b)&&(a=b)); }
template <class T> inline void cmin(T &a,T b){ ((a>b)&&(a=b)); }
const int N=310,P=998244353;
int n,m;
ll dp[N][N];
int s[N][N];
int main(){
rep(kase,1,rd()){
n=rd(),m=rd();
int fl=1;
memset(s,0,sizeof s);
rep(i,1,m) {
int a=rd(),b=rd();
if(a==b) fl=0;
else s[b][a]++;
}
rep(i,1,n) rep(j,1,n) s[i][j]+=s[i][j-1];
rep(i,1,n) rep(j,1,n) s[i][j]+=s[i-1][j];
if(!fl) {
puts("0");
continue;
}
memset(dp,0,sizeof dp);
rep(i,1,n+1) dp[i][i-1]=1;
drep(i,n,1) {
rep(j,i,n) {
rep(k,i,j) {
int t=s[k-1][j]-s[i-1][j]-s[k-1][k-1]+s[i-1][k-1];
if(t) continue;
t=s[j][k]-s[k][k]-s[j][k-1]+s[k][k-1];
if(t) continue;
dp[i][j]=(dp[i][j]+dp[i][k-1]*dp[k+1][j])%P;
}
}
}
printf("%lld\n",dp[1][n]);
}
}
\ [\ \]
\ [\ \]
[BZOJ4758] Usaco2017 월] 서브 시퀀스 취소
\ (DP [I] [J ] [A]는 [B] \) 나타낸다 \ ([I, J] \ ) 이 섹션의 \ (LIS를 \) 시작하고 종료 \ (A, B \) 답변
이어서 \ (DP [I-1] [J], DP [I] [J + 1] \) 전송 양면 역전 고려할 수
const int N=52,P=998244353;
int n;
int a[N];
int dp[N][N][N][N];
int main(){
rep(i,1,n=rd()) a[i]=rd();
rep(i,1,n) dp[i][i][a[i]][a[i]]=1;
rep(i,1,n-1) dp[i][i+1][min(a[i],a[i+1])][max(a[i],a[i+1])]=2;
drep(i,n,1) {
rep(j,i,n) {
if(i>1) {
rep(a,1,50) rep(b,a,50) {
cmax(dp[i-1][j][a][b],dp[i][j][a][b]);
if(::a[i-1]<=a) cmax(dp[i-1][j][::a[i-1]][b],dp[i][j][a][b]+1);
}
}
if(j<n) {
rep(a,1,50) rep(b,a,50) {
cmax(dp[i][j+1][a][b],dp[i][j][a][b]);
if(::a[j+1]>=b) cmax(dp[i][j+1][a][::a[j+1]],dp[i][j][a][b]+1);
}
}
if(i>1 && j<n) {
rep(a,1,50) rep(b,a,50) {
cmax(dp[i-1][j+1][a][b],dp[i][j][a][b]);
if(::a[j+1]<=a) cmax(dp[i-1][j+1][::a[j+1]][b],dp[i][j][a][b]+1);
if(::a[i-1]>=b) cmax(dp[i-1][j+1][a][::a[i-1]],dp[i][j][a][b]+1);
if(::a[j+1]<=a && ::a[i-1]>=b) cmax(dp[i-1][j+1][::a[j+1]][::a[i-1]],dp[i][j][a][b]+2);
}
}
}
}
int ans=0;
rep(i,1,50) rep(j,1,50) cmax(ans,dp[1][n][i][j]);
printf("%d\n",ans);
}
\ [\ \]
\ [\ \]
[BZOJ3379] Usaco2004 열기] 숙제 숙제 선삭
더 어려운 문제가 될 것 같다
사실, 우리가 이동하는 공간의 양쪽에 있어야 말할 수있는, 관찰, 다음의 중간으로 이동
방의 양측이 완료되지 않은 경우는 반드시 방의 양쪽 후 갈 수있는 방 가운데로 통과 것이기 때문에, 다음의 중간에 갈 필요가 없습니다
이 생각하는 경우, 단순히 것이다
template <class T> inline void cmax(T &a,T b){ ((a<b)&&(a=b)); }
template <class T> inline void cmin(T &a,T b){ ((a>b)&&(a=b)); }
const int N=1010,P=998244353;
int n,m;
typedef pair<int,int> Pii;
Pii a[N];
int dp[N][N][2];
int main(){
n=rd(),rd(),m=rd();
rep(i,1,n) a[i].first=rd(),a[i].second=rd();
sort(a+1,a+n+1);
memset(dp,10,sizeof dp);
dp[1][n][0]=max(a[1].second,a[1].first),dp[1][n][1]=max(a[n].second,a[n].first);
rep(i,1,n) {
drep(j,n,i) {
if(i>1) {
cmin(dp[i][j][0],dp[i-1][j][0]+abs(a[i].first-a[i-1].first));
cmin(dp[i][j][1],dp[i-1][j][0]+abs(a[j].first-a[i-1].first));
}
if(j<n) {
cmin(dp[i][j][0],dp[i][j+1][1]+abs(a[i].first-a[j+1].first));
cmin(dp[i][j][1],dp[i][j+1][1]+abs(a[j].first-a[j+1].first));
}
cmax(dp[i][j][0],a[i].second);
cmax(dp[i][j][1],a[j].second);
}
}
int ans=1e9;
rep(i,1,n) cmin(ans,min(dp[i][i][1],dp[i][i][0])+abs(a[i].first-m));
printf("%d\n",ans);
}
\ [\ \]
\ [\ \]
[BZOJ3928] Cerc2014] 우주 침입자
상기 범위를 제한 타입이
출력이 제한을 충족하는 가장 큰 한계 중 하나에서 섹션을 복용 각각은, 한계는 시간 샷 범위에서 선택
그래서 모든 점 간격이 파괴됩니다이 시간에이 간격에서
이 시점을 교차하지 마십시오 직접 플러스
#include<cstdio>
#include<cctype>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
#define reg register
typedef long long ll;
#define rep(i,a,b) for(reg int i=a,i##end=b;i<=i##end;++i)
#define drep(i,a,b) for(reg int i=a,i##end=b;i>=i##end;--i)
char IO;
int rd(){
int s=0,f=0;
while(!isdigit(IO=getchar())) if(IO=='-') f=1;
do s=(s<<1)+(s<<3)+(IO^'0');
while(isdigit(IO=getchar()));
return f?-s:s;
}
#define cmax(a,b) ((a<b)&&(a=b))
#define cmin(a,b) ((a>b)&&(a=b))
const int N=610;
int n;
int a[N],b[N],d[N];
int dp[N][N],ma[N][N];
int h[N],hc;
int main(){
rep(kase,1,rd()) {
hc=0;
n=rd();
rep(i,1,n) {
a[i]=rd(),b[i]=rd(),d[i]=rd();
h[++hc]=a[i];
h[++hc]=b[i];
}
sort(h+1,h+hc+1),hc=unique(h+1,h+hc+1)-h-1;
rep(i,1,hc) rep(j,i,hc) ma[i][j]=0,dp[i][j]=1e9;
rep(i,1,n) {
a[i]=lower_bound(h+1,h+hc+1,a[i])-h;
b[i]=lower_bound(h+1,h+hc+1,b[i])-h;
if(d[i]>d[ma[a[i]][b[i]]]) ma[a[i]][b[i]]=i;
}
rep(i,1,hc) rep(j,i+1,hc) {
((d[ma[i][j]]<d[ma[i][j-1]])&&(ma[i][j]=ma[i][j-1]));
rep(k,i,j-1) ((d[ma[i][j]]<d[ma[k][j]])&&(ma[i][j]=ma[k][j]));
}
rep(i,1,hc) dp[i][i]=d[ma[i][i]];
drep(i,hc,1) {
rep(j,i,hc) {
int id=::ma[i][j],ma=d[id];
if(!id) dp[i][j]=0;
else rep(k,a[id],b[id]) cmin(dp[i][j],dp[i][k-1]+dp[k+1][j]+ma);
}
}
printf("%d\n",dp[1][hc]);
}
}
\ [\ \]
\ [\ \]
POI2015 세척
주제 설명 :
행을 왼쪽에서 오른쪽으로 n 개의 세차이 있으며, 각 점포가 양수 가격 갖는다 \ (P- 형을 [I] \) .
이 \ (m의 \) 개인 소비는 올 \을 (내가 \) 개인이 먼저 통과 될 것 \을 (A [내가] \) 첫까지 시작 ([내가] \ B) \ 세차, 그리고 것은 선택합니다 소비자 번 싼 가게. 저렴한 가격보다 그러나 만약 \ (c는 [I]는 \) , 그 사람이 세차 아니다.
모든 돈의 합이 최대 소비 있도록, 각 점포의 가격을 지정하십시오.
기입
첫 번째 라인은 두 양의 정수 포함 \ (N-, m을 (1 <= N -. <= 50, 1 <= m <= 4000) \) .
이어서 세 양의 정수를 포함, 각 행, 행 M과 B \ (a [I]을, [I], C [i]는 (1 <= A [i]는 <= B를 [I] <= N 1 <= C [I] <= 500000) \ )
수출
출력의 첫 번째 줄의 총 사용량의 최대 값이 양의 정수.
제 2 출력 라인 (\ N- \) 은 각각 각 세차 가격에 대한 양의 정수이고, \ (P는 [I]는 \) 필요 \이. (1 <= P [I] <= 500000 \) .
복수 세트의 최적해 모든 출력의 그룹 인 경우.
보고서 문제 해결
또는 상기 타이틀의 간격에 제한은 여전히 정의 \ (DP가 [I]는 [j는 [K]는 \)은 모든 고려 나타내는 \ ([L, R] \ ) 된다 (\ [내가 J]가 \ ) 완전히 포함되고, 간격 최소 내의 \ (케이 \) 답변
열거 값 및 최소값은이 위치 응답의 모든 단면 형상을 고려하여 다음의 최소 값보다 크거나 같은 값의 양쪽에서 나타날하고
#include<cstdio>
#include<cctype>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
#include<bitset>
using namespace std;
#define reg register
typedef long long ll;
#define rep(i,a,b) for(reg int i=a,i##end=b;i<=i##end;++i)
#define drep(i,a,b) for(reg int i=a,i##end=b;i>=i##end;--i)
char IO;
int rd(){
int s=0,f=0;
while(!isdigit(IO=getchar())) if(IO=='-') f=1;
do s=(s<<1)+(s<<3)+(IO^'0');
while(isdigit(IO=getchar()));
return f?-s:s;
}
const int N=52,M=4010;
int n,m;
vector <int> G[N][N];
int dp[N][N][M],f[N][N][M];
int h[M],hc;
int s[N][N][M],sum[N][N][M];
int to[N][N][M];
inline void chk(int &a,int b){ ((a<b)&&(a=b)); }
void Solve(int l,int r) {
rep(i,l,r) {
rep(j,1,hc) {
int t=f[l][i-1][j]+f[i+1][r][j]+sum[l][r][j]-sum[l][i-1][j]-sum[i+1][r][j];
if(t>dp[l][r][j]) dp[l][r][j]=t,to[l][r][j]=i;
}
}
drep(j,hc,1) f[l][r][j]=max(dp[l][r][j],f[l][r][j+1]);
}
int res[N];
int dfs(int l,int r,int lim) {
if(l>r) return 0;
int ma=-1,id;
rep(i,lim,hc) if(dp[l][r][i]>ma) ma=dp[l][r][i],id=i;
res[to[l][r][id]]=id;
dfs(l,to[l][r][id]-1,id);
dfs(to[l][r][id]+1,r,id);
return ma;
}
int main(){
n=rd(),m=rd();
rep(i,1,m) {
int l=rd(),r=rd(),w=rd();
h[++hc]=w;
G[l][r].push_back(w);
}
sort(h+1,h+hc+1),hc=unique(h+1,h+hc+1)-h-1;
rep(l,1,n) rep(r,l,n) rep(i,1,hc) rep(j,0,G[l][r].size()-1) s[l][r][i]+=((G[l][r][j]>=h[i])?h[i]:0);
rep(k,1,hc) {
rep(l,1,n) {
rep(r,l,n) {
sum[l][r][k]=sum[l][r-1][k];
rep(i,l,r) sum[l][r][k]+=s[i][r][k];
}
}
} // 预处理区间l,r内最小值为k的答案
drep(i,n,1) {
rep(j,i,n) {
rep(k,1,hc) to[i][j][k]=i;
Solve(i,j);
}
}
printf("%d\n",dfs(1,n,1));
rep(i,1,n) printf("%d ",h[res[i]]);
puts("");
}
\ [\ \]
\ [\ \]
[BZOJ4856] [Jsoi2016] 바이러스 감염
나는 질문의 의미가 이해 :만큼 U 턴으로, 모든 돌아올 완료 저장하는 것이 필요하다
따라서, 우리는 간격의 섹션의 이전을 고려 간격은 가장 가까운 점을 해결하기 위해 돌아오고 포인트 먼 각 세그먼트 내에서 해결
각 간격 \ ([L, R] \ ) 의 기여가 밖으로 직접 전처리 될 수있다
간격 고려 \ ([L, R] \ ) , 각 포인트를, 또는 제의 규칙에 발생하거나, 다시 룰
기부 개의 각각 \ (SUM [R] -sum [I] \) (인해 여러 날까지 유지) \ (3 * (RI) * A [I] + A [I] \) (늦게 일)
(아마 같은 의미, 어떤 감정 이해, 내가 잘못 될 수있다)
재발이 될 수 있습니다
template <class T> inline void cmax(T &a,T b){ ((a<b)&&(a=b)); }
template <class T> inline void cmin(T &a,T b){ ((a>b)&&(a=b)); }
const int N=3010;
int n;
ll a[N];
ll dp[N];
ll sum[N];
ll s[N][N];
int main(){
n=rd();
rep(i,1,n) a[i]=rd(),sum[i]=sum[i-1]+a[i];
rep(i,1,n) {
drep(j,i,1) {
s[j][i]=s[j+1][i];
s[j][i]+=sum[i]-sum[j];
s[j][i]+=min(a[j]+(sum[i]-sum[j]),3*(i-j)*a[j]+a[j]);
}
}
memset(dp,63,sizeof dp);
ll ans=1e18;
dp[0]=0;
rep(i,1,n) {
rep(j,1,i) {
ll t=s[j][i]+(2*(i-j+1)+2*(i-j))*(sum[n]-sum[i]);
cmin(dp[i],dp[j-1]+t);
if(i==n) cmin(ans,dp[j-1]+s[j][i]+(2*(i-j+1)+(i-j))*(sum[n]-sum[i]));
}
}
printf("%lld\n",ans-sum[n]);
}
\ [\ \]
\ [\ \]
[BZOJ3971 [WF2013] Matrjoşka
문제를 이해하는 것은 너무 고통
아마, 각 세그먼트는 몇 단락으로 통합되는 것을 의미 \ ([1..x] \) 로 이루어지는
사실, 결합 기여 최소 지속 기간에 나타나는지 \ ([내가 K] \ ) 또는 \ ([K + 1, J ] \) 의 내부 개방하지 않고도 다른 기여 개방 될
template <class T> inline void cmin(T &a,T b){ ((a>b)&&(a=b)); }
template <class T> inline void cmax(T &a,T b){ ((a<b)&&(a=b)); }
const int N=510;
const char *Im="Impossible";
int n;
int dp[N][N],ans[N];
int a[N],cnt[N][N],c[N];
int mi[N][N],mk[N][N];
int main(){
rep(i,1,n=rd()) {
a[i]=rd();
cnt[i][a[i]]++;
if(a[i]>n) return puts(Im),0;
}
rep(i,1,n) rep(j,1,n) cnt[i][j]+=cnt[i][j-1];
rep(i,1,n) rep(j,1,n) cnt[i][j]+=cnt[i-1][j];
rep(i,1,n){
memset(c,0,sizeof c);
mk[i][i-1]=1;
mi[i][i-1]=1e9;
rep(j,i,n) {
mk[i][j]=mk[i][j-1];
if(++c[a[j]]>=2) mk[i][j]=0;
mi[i][j]=min(mi[i][j-1],a[j]);
}
}
memset(dp,63,sizeof dp);
rep(i,1,n) dp[i][i]=0;
drep(i,n,1) rep(j,i,n) if(mk[i][j]) {
rep(k,i,j-1) {
if(mi[i][k]<mi[k+1][j]) cmin(dp[i][j],dp[i][k]+dp[k+1][j]+(j-i+1)-(cnt[k][mi[k+1][j]]-cnt[i-1][mi[k+1][j]]));
else cmin(dp[i][j],dp[i][k]+dp[k+1][j]+(j-i+1)-(cnt[j][mi[i][k]]-cnt[k][mi[i][k]]));
}
}
memset(ans,63,sizeof ans);
ans[0]=0;
rep(i,1,n) drep(j,i,1) {
if(cnt[i][i-j+1]-cnt[j-1][i-j+1]==i-j+1) {
cmin(ans[i],ans[j-1]+dp[j][i]);
}
}
if(ans[n]<1e8) printf("%d\n",ans[n]);
else puts(Im);
}
\ [\ \]
\ [\ \]
[BZOJ4426] Nwerc2015] 생산성 향상 최대 생산성
더미 섹션으로 분할된다 \ (K \) 그룹 각각 지불 \ (> \ 0) , 교차점의 총 길이의 최대치
여기에서 우리는이 간격을 제거한다
먼저 간격 \ ([L, R] \ ) 우리 그리고, 다른 부분을 포함 할 수있는 경우, 두 사례의 결정
1. 그리고 그가 간격이 그룹에 포함 된,이 그룹의 기여에 영향을주지 않습니다
2. 자신의 그룹을 열 수있는 사람
제안 된 모든 다른 섹션 함유하고, 나머지 부분이 만나는 꼭된다 \ ([L, R] \ )은 증가, 우리가 사용하는이 섹션 \ (DP [I] [J ] \) 계산하기 전에 \ (나는 \ ) 으로 간격 \ (j \) 응답 기
기타 섹션, 우리는 무시하거나, 독립적 인 그룹에 가장 큰 기여 중 일부를 선택하는
이러한 전송 \ (DP \)는 실제로 분명하다 \합니다 (N- ^ 3 \) 있지만, 사실은 또한 실행되도록 최적화 할 수 있습니다 \ (n 개의 \의 당량 1000 \) 당신이 원하는 당신에게 신들을 떠나, 데이터를
template <class T> inline void cmin(T &a,T b){ ((a>b)&&(a=b)); }
template <class T> inline void cmax(T &a,T b){ ((a<b)&&(a=b)); }
const int N=210;
int n,m,c;
int dp[N][N];
int len[N],lc;
struct Node{
int l,r;
bool operator < (const Node __) const {
return r<__.r||(r==__.r&&l>__.l);
}
}A[N];
int main(){
n=rd(),m=rd();
rep(i,1,n) A[i].l=rd(),A[i].r=rd()-1;
sort(A+1,A+n+1);
int ma=-1;
rep(i,1,n) {
if(ma<A[i].l) ma=A[i].l,A[++c]=A[i];
else len[++lc]=A[i].r-A[i].l+1;
}
n=c;
memset(dp,-63,sizeof dp);
dp[0][0]=0;
rep(i,1,n) {
rep(j,1,i) {
drep(k,i,1) {
if(A[i].l<=A[k].r) cmax(dp[i][j],dp[k-1][j-1]+A[k].r-A[i].l+1);
else break;
}
}
}
int ans=0;
sort(len+1,len+lc+1,greater<int>());
rep(i,1,lc) len[i]+=len[i-1];
rep(i,max(1,m-lc),min(m,n)) cmax(ans,dp[n][i]+len[m-i]);
printf("%d\n",ans);
}