【区间DP】
【区间DP】
板子题
拓展题
可划分数组
https://ac.nowcoder.com/acm/contest/105825/E

#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef pair<int,int> PII;
typedef long long ll;
const int INF=0x3f3f3f3f;
ll abss(ll a){return a>0?a:-a;}
ll max_(ll a,ll b){return a>b?a:b;}
ll min_(ll a,ll b){return a<b?a:b;}
bool cmpll(ll a,ll b){return a>b;}
const int N=2e3+10;
int n;
int a[N];
int pre[N],nxt[N];
//pre:在pre[i]前的第一个不互质的数
//nxt:在nxt[i]后的第一个不互质的数
int dp[N];
int gcd(int a,int b){
return b?gcd(b,a%b):a;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
//算pre和nxt
for(int i=1;i<=n;i++){
for(int j=i-1;j>=1;j--){
if(gcd(a[i],a[j])!=1){
pre[i]=j;
break;
}
}
}
for(int i=1;i<=n;i++){
nxt[i]=n+1;//记得初始化n+1(最右边!)
for(int j=i+1;j<=n;j++){
if(gcd(a[i],a[j])!=1){
nxt[i]=j;
break;
}
}
}
//对dp数组初始化:初始化长度为1的和为2的
for(int r=2;r<=n;r++){//r从2开始
dp[r]=1;
for(int i=1;i<=r;i++){
//不满足条件=0:pre和nxt
if(!(pre[i]>=1 || nxt[i]<=r)) dp[r]=0;
}
}
//[l,i][i+1,r]
//i从2枚举到n-2->r从4枚举到n
for(int r=4;r<=n;r++){
//如果nxt[r]取得到:没必要先取pre,直接INF
int minpre=nxt[r]>r?pre[r]:INF;
for(int i=r-1;i>=3;i--){//枚举i+1 双指针式扩展
if(nxt[i]>r) minpre=min(minpre,pre[i]);//扩展条件
if(minpre>=i && dp[i-1]!=0){//判断两个条件均满足
dp[r]=max(dp[r],dp[i-1]+1);//注意这里-1是因为枚举的i+1
}
}
}
if(dp[n]==0){
cout<<"-1";
return 0;
}
cout<<dp[n];
return 0;
}
Iron Bars Cutting
https://ac.nowcoder.com/acm/contest/108298/I
题目大意


思路



->sort不平衡度小->大/区间小->大
dp[l][r]=min(dp[l][r],dp[l][k]+dp[k+1][r]+贡献)
记得初始化dp[i][i]=0
代码
int n;
void solve(){
cin>>n;
vector<i64> a(n+1,0);
vector<i64> pre(n+1,0);
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=n;i++) pre[i]=pre[i-1]+a[i];
int len=0;
for(int i=1;i<=n;i++){
for(int j=i+1;j<=n;j++){
for(int k=i;k<j;k++){
len++;
}
}
}
vector<array<i64,4>> pos(len);
int cnt=0;
for(int i=1;i<=n;i++){
for(int j=i+1;j<=n;j++){
for(int k=i;k<j;k++){
i64 l1=pre[k]-pre[i-1],l2=pre[j]-pre[k];
i64 val=min64(l1,l2)*(__lg(l1+l2-1LL)+1LL);
pos[cnt++]={i,j,k,val};
}
}
}
sort(pos.begin(),pos.end(),
[&](array<i64,4> x,array<i64,4> y)->bool{
auto [l1,r1,k1,v1]=x;
auto [l2,r2,k2,v2]=y;
i64 c1=llabs((pre[k1]-pre[l1-1])-(pre[r1]-pre[k1]));
i64 c2=llabs((pre[k2]-pre[l2-1])-(pre[r2]-pre[k2]));
if(c1==c2){
return (r1-l1+1)<(r2-l2+1);
}
else{
return c1<c2;
}
});
vector<i64> res(n+1,1e18);
vector<vector<i64>> dp(n+1,vector<i64>(n+1,1e18));
//初始化
for(int i=1;i<=n;i++){
dp[i][i]=0;
}
for(auto [l,r,k,v]:pos){
i64 cv=dp[l][k]+dp[k+1][r]+v;
dp[l][r]=min64(dp[l][r],cv);
if(l==1 && r==n){
res[k]=cv; //更新的是算得到的
}
}
for(int i=1;i<n;i++){
if(res[i]>=1e18) cout<<-1<<" ";
else cout<<res[i]<<" ";
}
cout<<endl;
}

浙公网安备 33010602011771号