当前位置: 首页 > article >正文

G - Merchant Takahashi / F - Useless for LIS

G - Merchant Takahashi

首先考虑暴力 DP。

设最后一步走到编号 ii 的城镇的方案的最大收益为 fifi​,则每次集市相当于是 fTi←fj−C∣Ti−j∣+Pi(1≤j≤n)。

这样每次可以通过枚举 j 来转移,这样总时间复杂度是 O(nm) 的,无法通过。

考虑优化 DP,先拆绝对值,把转移分为以下两类:

  • fTi​​←fj​−C(Ti​−j)+Pi​(1≤j≤Ti​),即 fTi​​←(fj​+C⋅j)+(−C⋅Ti​+Pi​)。

    注意到后面部分是定值而前面部分与 i 无关,j 的取值范围又是一段前缀,所以我们用树状数组维护 fj​+C⋅j 的前缀最大值。

  • ffTi​​←fj​−C(j−Ti​)+Pi​(Ti​≤j≤n),即 fTi​​←(fj​−C⋅j)+(C⋅Ti​+Pi​)。

    同理我们用树状数组维护 fj​−C⋅j 的后缀最大值。怎样用树状数组维护后缀信息?只需交换两个循环循序即可。

然后我们把 fTi​​ 插入到树状数组的Ti​ 位置去。

初始状态为 f1​=0,最后答案为 最大的f i。注意代码中的 fifi​ 表示的是上文的 fTi.

代码:

#include <bits/stdc++.h>
#define int long long
#define fi first
#define se second
#define all(v) v.begin(),v.end()
using namespace std;
const int inf = 0x3f3f3f3f3f3f3f;
const int N = 2e5+5;
int n,m,c;
int dp[N];
int v[N],w[N];
int tr1[N];//求小于等于x的最大值
int tr2[N];//求大于等于x的最大值

int lowbit(int x){
    return x&(-x);
}

void add1(int x,int c){
    for(int i=x;i<=n;i+=lowbit(i)){
        tr1[i] = max(tr1[i],c);
    }
    return;
}

int ask1(int x){
    int res = -inf;
    for(int i=x;i>=1;i-=lowbit(i)){
        res = max(res,tr1[i]);
    }
    return res;
}

void add2(int x,int c){
    for(int i=x;i>=1;i-=lowbit(i)){
        tr2[i] = max(tr2[i],c);
    }   
    return;
}

int ask2(int x){
    int res = -inf;
    for(int i=x;i<=n;i+=lowbit(i)){
        res = max(res,tr2[i]);
    }
    return res;
}

void solve(){
    cin>>n>>c;
    cin>>m;

    memset(tr1,-0x3f3f3f,sizeof(tr1));
    memset(tr2,-0x3f3f3f,sizeof(tr2));
    add1(1,c);
    add2(1,-c);
    dp[0] = 0;

    int ans = 0;
    
    for(int i=1;i<=m;i++){
        int x,y;cin>>x>>y;
        int t = ask1(x) + (y-c*x);
        int tt = ask2(x) + (y+c*x);

        dp[i] = max(t,tt);
        ans = max(ans,dp[i]);

        add1(x,dp[i]+c*x);
        add2(x,dp[i]-c*x);

    }

    cout<<ans<<"\n";


}

signed main(){
    int T=1;
    //cin>>T;
    while(T--){
        solve();
    }

    return 0;
}

F - Useless for LIS

双倍经验:

算法依旧是树状数组加dp,f [ i ]表示前缀的最大长度,g [ i ] 表示后缀的最大长度,那么 i 的最大长度为 f [ i ] + g [ i ] - 1(减去重复元素)

 代码:

#include <bits/stdc++.h>
#define int long long
#define fi first
#define se second
#define all(v) v.begin(),v.end()
using namespace std;
const int inf = 0x3f3f3f3f3f3f3f;
const int N = 2e5+5;
int n;
int a[N];
int f[N],g[N];
int tr1[N],tr2[N];
map<int,int>mp;

int lowbit(int x){
    return x&(-x);
}

void add1(int x,int c){//加到前面
    for(int i=x;i<=n;i+=lowbit(i)){
        tr1[i] = max(tr1[i],c);
    }
    return;
}

int ask1(int x){
    int res = 0;
    for(int i=x;i>=1;i-=lowbit(i)){
        res = max(res,tr1[i]);
    }
    return res;
}

void add2(int x,int c){//加到后面
    for(int i=x;i>=1;i-=lowbit(i)){
        tr2[i] = max(tr2[i],c);
    }
    return;
}

int ask2(int x){
    int res = 0;
    for(int i=x;i<=n;i+=lowbit(i)){
        res = max(res,tr2[i]);
    }
    return res;
}

void solve(){
    cin>>n;
    mp.clear();
    for(int i=0;i<=n+1;i++)f[i] = g[i] = 0;
    for(int i=0;i<=n+1;i++){
        tr1[i] = tr2[i] = 0;
    }
    for(int i=1;i<=n;i++)cin>>a[i];
    vector<int>b;//离散化
    for(int i=1;i<=n;i++){
        if(mp[a[i]])continue;
        mp[a[i]] = 1;
        b.push_back(a[i]);
    }
    sort(all(b));
    for(int i=1;i<=n;i++){
        int t = lower_bound(all(b),a[i]) - b.begin();
        a[i] = t+1;
    }

    int len = 0;//求前缀
    for(int i=1;i<=n;i++){
        f[i] = ask1(a[i]-1) + 1;
        add1(a[i],f[i]);
        len = max(len,f[i]);
    }
    
    /*for(int i=1;i<=n;i++){
        for(int j=i-1;j>=1;j--){
            if(a[i]>a[j]){
                f[i] = max(f[i],f[j]+1);
                len = max(len,f[i]);
            }
        }
    }
    */

    for(int i=n;i>=1;i--){//求后缀
        g[i] = ask2(a[i]+1) + 1;
        add2(a[i],g[i]);
    }

    vector<int>ans;
    for(int i=1;i<=n;i++){
        if(f[i]+g[i]-1 == len){//如果前面的长度加上后面的长度为最长,那么就选
            ans.push_back(i);
        }
    }

    cout<<ans.size()<<"\n";
    for(int i=0;i<ans.size();i++){
        cout<<ans[i]<<" ";
    }
    cout<<"\n";


}

signed main(){
    int T=1;
    cin>>T;
    while(T--){
        solve();
    }

    return 0;
}


http://www.kler.cn/a/316507.html

相关文章:

  • ARM架构中断与异常向量表机制解析
  • vue请求数据报错,设置支持跨域请求,以及2种请求方法axios或者async与await
  • 数字后端教程之Innovus report_property和get_property使用方法及应用案例
  • 相机光学(四十二)——sony的HDR技术
  • python: postgreSQL using psycopg2 or psycopg
  • 文献解读-DNAscope: High accuracy small variant calling using machine learning
  • mysql学习教程,从入门到精通,TOP 和MySQL LIMIT 子句(15)
  • 本地连线上Redis访问不通
  • SpringBoot权限认证-Sa-Token的使用与详解
  • C++第十二节课 模板初阶和string引入
  • Apache Flink 流批融合技术介绍
  • 安装vue 试了很多镜像不成功, 最后找到了
  • Sentence Transformers 教程!
  • LeetCode_sql_day28(1767.寻找没有被执行的任务对)
  • STM32 通过软件模拟 I2C 驱动 24Cxx 系列存储器
  • 沙盒的一机两用能否运用在源代码加密方面呢?
  • 随手记:前端一些定位bug的方法
  • java Class类与Field、Method、Constructor类
  • 大数据毕业设计选题推荐-网络电视剧收视率分析系统-Hive-Hadoop-Spark
  • 【网络编程】网页的显示过程
  • 软件工程的七条基本原理
  • JdbcTemplate常用方法一览AG网页参数绑定与数据寻址实操
  • pick你的第一个人形机器人——青龙强化学习环境测试
  • Vuex 入门与实战
  • CMake 教程(五):安装和测试
  • [全网首篇]关于 VMSA-2024-0019 安全公告(CVE-2024-38812、CVE-2024-38813)的说明与解决方案