zoukankan      html  css  js  c++  java
  • 最大得分 题解(线段树维护dp)

    题目链接

    题目思路

    大部分人使用的是三维dp,只有我这个fw用的阴间线段树维护dp

    首先很容易想到一个(dp)

    (dp[i][j])表示前(i)个元素分为(j)个段的最大值

    转移方程就是(dp[i][j]=max(dp[x][j-1]+gcd(a[x+1],a[x+2]...a[i])) (1le x le i-1))

    答案就是(dp[n][k]) 但是这样的复杂度很明显就是(O(n^2k)) 妥妥的(TLE)

    但是你可以将(gcd(a[x+1],a[x+2]...a[i]))这些元素分类,最多只有100种,因为(a[i]le 100)

    而且你会发现若是固定右端点,枚举左端点的连续那么对于相同(gcd(a[x+1],a[x+2]...a[i]))

    所对应的位置一定是连续的

    (vec[i][j][0])表示以(a[i])为右端点,最左的(pos)使得(gcd(a[pos],a[pos+1],...a[i])=j)

    (vec[i][j][1])表示以(a[i])为右端点,最右的(pos)使得(gcd(a[pos],a[pos+1],...a[i])=j)

    然后用线段树维护这个区间的值即可,细节有点多

    代码

    #include<bits/stdc++.h>
    #define debug printf("
     I am here
    ");
    #define fi first
    #define se second
    typedef long long ll;
    const int maxn=1e4+5,inf=0x3f3f3f3f,mod=1e9+7;
    using namespace std;
    int n,k;
    int a[maxn];
    int cal[105][105];
    vector<int> vec[maxn][105];
    int ma[maxn],mi[maxn];
    int tree[maxn<<2][55];
    int dp[maxn][55];
    int pre[maxn];
    void update(int node,int pos,int l,int r,int val,int id){
        if(l==r){
            tree[node][id]=val;
            return ;
        }
        int mid=(l+r)/2;
        if(mid>=pos) update(node<<1,pos,l,mid,val,id);
        else update(node<<1|1,pos,mid+1,r,val,id);
        tree[node][id]=max(tree[node<<1][id],tree[node<<1|1][id]);
    }
    int query(int node,int L,int R,int l,int r,int id){
        if(L>R) return -inf;
        if(L<=l&&r<=R){
            return tree[node][id];
        }
        int mid=(l+r)/2,ma=-inf;
        if(mid>=L) ma=max(ma,query(node<<1,L,R,l,mid,id));
        if(mid<R) ma=max(ma,query(node<<1|1,L,R,mid+1,r,id));
        return ma;
    }
    void build(int node,int l,int r){
        for(int i=1;i<=40;i++){
            tree[node][i]=-inf;
        }
        if(l==r){
            return ;
        }
        int mid=(l+r)/2;
        build(node<<1,l,mid);
        build(node<<1|1,mid+1,r);
    }
    int main(){
        scanf("%d%d",&n,&k);
        build(1,1,n);
        for(int i=1;i<=100;i++){
            for(int j=1;j<=100;j++){
                cal[i][j]=__gcd(i,j);
                // cal[i][j]表示i和j的gcd
            }
        }
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
        }
        for(int i=1;i<=n;i++){
            for(int j=1;j<=100;j++){
                ma[j]=-inf;
                mi[j]=inf;
            }
            int temp=a[i];
            for(int j=i;j>=1;j--){
                temp=cal[temp][a[j]];
                mi[temp]=min(mi[temp],j);
                ma[temp]=max(ma[temp],j);
            }
            for(int j=1;j<=100;j++){
                if(mi[j]==inf) continue;
                vec[i][j].push_back(mi[j]);
                vec[i][j].push_back(ma[j]);
            }
        }
        for(int i=0;i<=n;i++){
            for(int j=0;j<=50;j++){
                dp[i][j]=-inf;
            }
        }
        for(int i=1;i<=n;i++){
            pre[i]=__gcd(pre[i-1],a[i]);
        }
        // dp[i][j] 表示前i个分为j个段
        for(int i=1;i<=n;i++){
            for(int j=1;j<=min(i,k);j++){
                if(j==1){
                    dp[i][j]=pre[i];
                }else{
                    for(int u=1;u<=100;u++){
                        if(vec[i][u].size()==0) continue;
                        int x=query(1,max(vec[i][u][0]-1,1),vec[i][u][1]-1,1,n,j-1);
                        dp[i][j]=max(dp[i][j],x+u);
                    }
                }
                update(1,i,1,n,dp[i][j],j);
            }
        }
        printf("%d
    ",dp[n][k]);
        return 0;
    }
    
    
    卷也卷不过,躺又躺不平
  • 相关阅读:
    主成分分析
    8、特征选择
    7.逻辑回归实践
    6--逻辑回归
    《四分之四团队》:团队项目选题报告
    计算与软件工程 作业五
    计算与软件工程 作业四
    计算与软件工程 作业三
    计算与软件工程 作业二
    计算与软件工程作业一
  • 原文地址:https://www.cnblogs.com/hunxuewangzi/p/14711469.html
Copyright © 2011-2022 走看看