海亮 7.14 dp专题2
海亮 7.14 dp专题2
学考日 但是题还是要补的()
New Year Domino
不难发现区间内的答案就是将区间内所有多米诺骨牌放倒 剩余的空位个数
那么我们可以倍增优化一下
查询时直接从大向小跳即可
注意 如果可以覆盖到所有点 那么
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
const int N = 2e5 + 5;
int read ()
{
int x = 0 , f = 1;
char ch = cin.get();
while ( !isdigit ( ch ) ) { if ( ch == '-' ) f = -1; ch = cin.get(); }
while ( isdigit ( ch ) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = cin.get(); }
return x * f;
}
int n , p[N] , l[N] , q , f[N][31] , g[N][31] , len[N];
//如果越界 father就是0
signed main ()
{
ios::sync_with_stdio(false);
cin.tie(0) , cout.tie(0);
n = read();
for ( int i = 1 ; i <= n ; i ++ ) p[i] = read() , l[i] = read();
q = read();
for ( int i = n - 1 ; i ; i -- )
{
int temp = i + 1; len[i] = p[i] + l[i];
while ( temp && p[temp] <= p[i] + l[i] ) len[i] = max ( len[i] , len[temp] ) , temp = f[temp][0];
f[i][0] = temp , g[i][0] = p[temp] - len[i];
}
for ( int j = 1 ; j <= 30 ; j ++ ) for ( int i = 1 ; i <= n ; i ++ ) f[i][j] = f[f[i][j-1]][j-1] , g[i][j] = g[f[i][j-1]][j-1] + g[i][j-1];
while ( q -- )
{
int l = read() , r = read();
if ( f[l][0] > r ) cout << 0 << endl;
else
{
int res = 0;
for ( int j = 30 ; j >= 0 ; j -- ) if ( f[l][j] && f[l][j] <= r ) res += g[l][j] , l = f[l][j];
cout << res << endl;
}
}
return 0;
}
Sum Over Zero
非常艰难的一道题 因为需要用到
最终决定弃用数组离散化 改用
考虑朴素
这个东西可以将
将
那么在查询的时候查询所有下标小于等于
必须注意
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define mid ((l+r)>>1)
#define ls(p) t[p].son[0]
#define rs(p) t[p].son[1]
#define lson ls(p),l,mid
#define rson rs(p),mid+1,r
#define int long long
const int N = 2e5 + 5;
const int inf = 0x3f3f3f3f3f3f3f3f;
int read ()
{
int x = 0 , f = 1;
char ch = cin.get();
while ( !isdigit ( ch ) ) { if ( ch == '-' ) f = -1; ch = cin.get(); }
while ( isdigit ( ch ) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = cin.get(); }
return x * f;
}
int n , a[N] , f[N] , rt , sum[N];
struct DQY
{
struct node { int son[2] , val; } t[N<<5];
int tot = 0;
int new_node ( int p ) { t[++tot] = { { 0 , 0 } , -inf }; return tot; }
void upd ( int &p , int l , int r , int x , int val )
{
if ( !p ) p = new_node(p);
t[p].val = max ( t[p].val , val );
if ( l == r ) return;
if ( x <= mid ) upd ( lson , x , val );
else upd ( rson , x , val );
}
int query ( int p , int l , int r , int x , int y )
{
if ( !p ) return -inf;
if ( x <= l && r <= y ) return t[p].val;
int res = -inf;
if ( x <= mid ) res = max ( res , query ( lson , x , y ) );
if ( mid + 1 <= y ) res = max ( res , query ( rson , x , y ) );
return res;
}
}T;
vector<int> lsh;
signed main ()
{
ios::sync_with_stdio(false);
cin.tie(0) , cout.tie(0);
n = read();
for ( int i = 1 ; i <= n ; i ++ ) a[i] = read() , sum[i] = sum[i-1] + a[i];//维护一个前缀数组 这样一个合法的子段[j+1,i]就是a[i]-a[j]>=0的了
for ( int i = 0 ; i <= n ; i ++ ) lsh.push_back(sum[i]);
sort ( lsh.begin() , lsh.end() );
unique ( lsh.begin() , lsh.end() );
int sz = lsh.size();
for ( int i = 0 ; i <= n ; i ++ ) sum[i] = lower_bound ( lsh.begin() , lsh.end() , sum[i] ) - lsh.begin() + 1;
T.upd ( rt , 1 , sz , sum[0] , 0 );
for ( int i = 1 ; i <= n ; i ++ )
{
f[i] = max ( f[i-1] , T.query ( rt , 1 , sz , 1 , sum[i] ) + i );
T.upd ( rt , 1 , sz , sum[i] , f[i] - i );
}
cout << f[n] << endl;
return 0;
}
Hot Start Up (hard version)
首先可以想到朴素
考虑优化
也就是
分两种情况转移:
和 在同一个 上运行 也就是这次的另一个 上运行的是程序 这个 上次运行
dp[i][j] = min(dp[i][j],dp[i - 1][j] + (a[i] == a[i - 1] ? hot[a[i]] : cold[a[i]]));
和 在不同的 上运行 也就是这次的另一个 上运行的是程序 这个 上次运行 这次运行
dp[i][a[i - 1]] = min(dp[i][a[i - 1]],dp[i - 1][j] + (a[i] == j ? hot[a[i]] : cold[a[i]]));
这个已经可以过
那么对于
代码里加了一些解释()
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define mid (l+r>>1)
#define ls p<<1
#define rs p<<1|1
#define lson ls,l,mid
#define rson rs,mid+1,r
#define int long long
const int N = 3e5 + 5;
const int inf = 0x3f3f3f3f3f3f3f3f;
int read ()
{
int x = 0 , f = 1;
char ch = cin.get();
while ( !isdigit ( ch ) ) { if ( ch == '-' ) f = -1; ch = cin.get(); }
while ( isdigit ( ch ) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = cin.get(); }
return x * f;
}
int n , k , a[N] , cold[N] , hot[N];
struct DQY
{
struct node { int val , add; } t[N<<2];
void up ( int p ) { t[p].val = min ( t[p<<1].val , t[p<<1|1].val ); }
void changeadd ( int p , int val ) { t[p].val += val , t[p].add += val; }
void down ( int p )
{
if ( t[p].add )
{
changeadd ( ls , t[p].add );
changeadd ( rs , t[p].add );
t[p].add = 0;
}
}
void build ( int p , int l , int r )
{
if ( l == r ) return t[p].val = inf , void ();
build ( lson ) , build ( rson ) , up(p);
}
void minn ( int p , int l , int r , int x , int val )
{
if ( l == r ) return t[p].val = min ( t[p].val , val ) , void();
down(p);
if ( x <= mid ) minn ( lson , x , val );
else minn ( rson , x , val );
up(p);
}
void upd ( int p , int l , int r , int x , int y , int val )
{
if ( x <= l && r <= y ) return changeadd(p,val) , void();
down(p);
if ( x <= mid ) upd ( lson , x , y , val );
if ( mid + 1 <= y ) upd ( rson , x , y , val );
up(p);
}
int query ( int p , int l , int r , int x , int y )
{
if ( x <= l && r <= y ) return t[p].val;
down(p); int res = inf;
if ( x <= mid ) res = min ( res , query ( lson , x , y ) );
if ( mid + 1 <= y ) res = min ( res , query ( rson , x , y ) );
return res;
}
}T;
signed main ()
{
ios::sync_with_stdio(false);
cin.tie(0) , cout.tie(0);
int t = read();
while ( t -- )
{
n = read() , k = read();
for ( int i = 1 ; i <= n ; i ++ ) a[i] = read();
for ( int i = 1 ; i <= k ; i ++ ) cold[i] = read();
for ( int i = 1 ; i <= k ; i ++ ) hot[i] = read();
/*
for(int j = 0; j <= k; j++) {
dp[i][j] = min(dp[i][j],dp[i - 1][j] + (a[i] == a[i - 1] ? hot[a[i]] : cold[a[i]]));//ith program on CPU2
dp[i][a[i - 1]] = min(dp[i][a[i - 1]],dp[i - 1][j] + (a[i] == j ? hot[a[i]] : cold[a[i]]));//ith program on CPU1
}
这是朴素dp
*/
T.build ( 1 , 1 , k + 1 );//为了方便线段树 我们强制将所有下标加一
T.minn ( 1 , 1 , k + 1 , 1 , 0 );//注意这里 dp[0][0]状态也是合法的 否则你无法开始转移 dp[0][1--k]状态都是不合法的 因为这些点上还没跑过程序
for ( int i = 1 ; i <= n ; i ++ )
{
int temp = min ( T.query ( 1 , 1 , k + 1 , 1 , k + 1 ) + cold[a[i]] , T.query ( 1 , 1 , k + 1 , a[i] + 1 , a[i] + 1 ) + hot[a[i]] );
//相当于预处理第二个转移 前半句代码相当于朴素dp的a[i]!=j的情况 后半句相当于a[i]==j的情况
T.upd ( 1 , 1 , k + 1 , 1 , k + 1 , a[i] == a[i-1] ? hot[a[i]] : cold[a[i]] );//这里我们全局加 (a[i] == a[i - 1] ? hot[a[i]] : cold[a[i]])(这是第一个转移)
T.minn ( 1 , 1 , k + 1 , a[i-1] + 1 , temp );
}
cout << T.query ( 1 , 1 , k + 1 , 1 , k + 1 ) << endl;
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)