zoukankan      html  css  js  c++  java
  • fzyzojP2984 -- 序列变换问题

    一个区间缩小变换的问题,并且n<=300

    启示我们区间dp

    我们考虑最后一定是在原串上扣一些,剩一些

    所以不妨前求出[l,r]把[l,r]完全处理成什么样子的方案数

    然后再来一遍序列dp,统计答案

    (并且发现,每次消除其实是减去k-1个,换句话说,对于l,l+k-1,l+2k-1,消除一次之后,还可以再消除,直到最后剩一个,所以考虑关于mod(k-1)的同余位置)

    关于g对f的转移,就是我们考虑[l,r]最后一次是从什么消过来的

    关于g自己的转移,考虑最后一部分会消成什么样。(最后一个位置不消掉,就是从f[r][r][0/1]转移过来)

    代码:

    #include<bits/stdc++.h>
    #define il inline
    #define reg register int
    #define numb (ch^'0')
    using namespace std;
    typedef long long ll;
    il void rd(int &x){
        char ch;bool fl=false;
        while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
        for(x=numb;isdigit(ch=getchar());x=x*10+numb);
        (fl==true)&&(x=-x);
    }
    namespace Miracle{
    const int N=303;
    const ll inf=0x3f3f3f3f3f3f3f3f;
    ll f[303][303][2],g[303][10][1<<8],h[303];
    int a[N];
    int c[1<<8],w[1<<8];
    int n,k;
    int main(){
        rd(n);rd(k);
        for(reg i=1;i<=n;++i) rd(a[i]);
        for(reg i=0;i<(1<<k);++i){
            rd(c[i]);rd(w[i]);
        }
        memset(f,0xcf,sizeof f);
        for(reg i=1;i<=n;++i){
            f[i][i][a[i]]=0;
        }
        for(reg l=n;l>=1;--l){
            for(reg i=l-1;i<=n;++i){
                memset(g[i],0xcf,sizeof g[i]);
            }
            g[l-1][0][0]=0;
            g[l][1][a[l]]=0;
            for(reg r=l;r<=n;++r){
                for(reg i=r;i>l;i-=(k-1)){
                    for(reg t=1;t<=k&&t<=i-l+1;++t){
                        for(reg s=0;s<(1<<(t-1));++s){
                            g[r][t][s<<1]=max(g[r][t][s<<1],g[i-1][t-1][s]+f[i][r][0]);
                            g[r][t][s<<1|1]=max(g[r][t][s<<1|1],g[i-1][t-1][s]+f[i][r][1]);
                        }
                    }
                }
                if((r-l)%(k-1)==0){
                    for(reg s=0;s<(1<<k);++s){
                        f[l][r][c[s]]=max(f[l][r][c[s]],w[s]+g[r][k][s]);
                    }
                    g[r][1][0]=max(g[r][1][0],f[l][r][0]);
                    g[r][1][1]=max(g[r][1][1],f[l][r][1]);
                }
            }
        }
        memset(h,0xcf,sizeof h);
        h[0]=0;
        for(reg i=1;i<=n;++i){
            h[i]=h[i-1];
            for(reg j=i;j>=1;j-=(k-1)){
                h[i]=max(h[i],h[j-1]+f[j][i][0]);
                h[i]=max(h[i],h[j-1]+f[j][i][1]);
            }
        }
        printf("%lld
    ",h[n]);
        return 0;
    }
    
    }
    signed main(){
        freopen("3.in","r",stdin);
        freopen("3.out","w",stdout);
        Miracle::main();
        return 0;
    }
    
    /*
       Author: *Miracle*
       Date: 2019/2/9 18:19:41
    */

    就是考虑“统计消去[l,r]的”,再来一次统计“在原序列上消去”

  • 相关阅读:
    C# 四种基本排序算法(冒泡排序,插入排序,选择排序,快速排序)外加折半排序
    jQuery ajax serialize() 方法
    关于问问题
    VIM键位图
    Highcharts选项配置详细说明文档
    awk处理文件内容格式
    【转】如何写出高性能SQL语句
    PHP合并、追加与连接数组
    如何选择web开发语言
    PHP 数据类型验证和获取
  • 原文地址:https://www.cnblogs.com/Miracevin/p/10358447.html
Copyright © 2011-2022 走看看