• HDU5693


    HDU5693


    做法:

    1. 同hdu2476也时两次dp的题,首先可以列出方程(f[i] = max(f[i-1], max(f[j-1]+(i-j+1))*can[j][i]))(can[j][i])表示从j到i能否完全消除。
    2. 现在考虑如何求出(can[l][r]),还是区间dp,任何一个长度≥2的等差数列,都可以拆分为长度为2或3的等差数列的组合,于是可以列出转移方程,对于([l,r])我们有以下几种转移:
    • 当a[l],a[r]是符合要求的等差数列时,(can[l][r] |= can[l+1][r-1])
    • 当a[l],a[r]不是时,枚举中间的位置 $ can[l][r] |= (can[l][k-1]·can[k][r]) $
    • 当a[l],a[p],a[r] (p时l,r之间的一个位置) 是符合要求的等差数列时,根据情况把区间拆成几个部分,其中最普通的情况为(can[l][r] |= can[l+1][p-1]·can[p+1][r-1])
    • 当不存在这样的p时,直接枚举中间位置转移

    实现时,一定要注意细节,一些地方的特判不足都会wa,我这里单独计算区间长度为2,3的答案才能ac

    #include <bits/stdc++.h>
    #define rep(i,a,b) for(int i=a;i<=b;++i)
    #define per(i,a,b) for(int i=a;i>=b;--i)
    #define pb push_back
    const int N = 300 + 17;
    const int inf = 0x3f3f3f3f;
    typedef long long ll;
    using namespace std;
    int n, m, f[N];
    ll a[N], d;
    bool can[N][N];
    map<ll,bool> M;
    int fd(int l,int r,ll x) {
        rep(i,l,r)if(a[i]==x)return i;
        return -1;
    }
    void init_can() {
        memset(can,0,sizeof(can));
        rep(i,1,n-1) if(M.find((a[i+1]-a[i]))!=M.end())can[i][i+1]=1;
        rep(L,3,n) rep(l,1,n-L+1) {
            int r = l + L - 1;
            if(L == 3) { //***特判!!!
                if(a[l+1]*2==a[r]+a[l]&&M.find(a[l+1]-a[l])!=M.end()) can[l][r] = 1;
                else can[l][r] = 0;
                continue;
            }
            if(M.find((a[r]-a[l]))!=M.end()) {
                if(l+1==r) can[l][r] = 1;
                else can[l][r] |= can[l+1][r-1];
            }
            int p = fd(l+1,r-1,(a[r]+a[l])/2);
            if(abs(a[r]-a[l])%2==0&&p!=-1&&M.find((a[r]-a[l])/2)!=M.end()){
                if(l+1==p&&p+1==r) can[l][r] = 1;
                else if(l+1==p) can[l][r] |= can[p+1][r-1];
                else if(p+1==r) can[l][r] |= can[l+1][p-1];
                else can[l][r] |= (can[p+1][r-1]&can[l+1][p-1]);
            }
            rep(k,l+1,r) can[l][r] |= (can[l][k-1]&can[k][r]);
        }
    }
    
    int main() {
        //freopen("in.txt","r",stdin);
        int T;
        scanf("%d",&T);
        while(T--) {
            M.clear();
            scanf("%d%d",&n,&m);
            rep(i,1,n) scanf("%I64d",&a[i]);
            rep(i,1,m) scanf("%I64d",&d),M[d]=1;
            init_can();
            memset(f,0,sizeof(f));
            f[0] = f[1] = 0;
            rep(i,2,n) {
                f[i] = f[i-1];
                rep(j,1,i-1) if(can[j][i]) f[i] = max(f[i],f[j-1]+(i-j+1));
            }
            printf("%d
    ",f[n]);
        }
        return 0;
    }
    
    
  • 相关阅读:
    DataFrame的iloc与loc的区别是什么?
    [笔记]《算法图解》第十一章 接下来如何做
    [笔记]《算法图解》第十章 K最近邻算法
    leetcode NO.171 Excel表列序号 (python实现)
    [笔记]《算法图解》第九章 动态规划
    [笔记]《算法图解》第八章 贪婪算法
    [笔记]《算法图解》第七章 狄克斯特拉算法
    leetcode NO.7 反转整数 (python3实现)
    [错误处理]电脑风扇很响处理方案
    比对两文件夹下文件名的区别
  • 原文地址:https://www.cnblogs.com/RRRR-wys/p/9438746.html
Copyright © 2020-2023  润新知