• SUBTRACT


    SUBTRACT

    给出一个长度为n序列({a_i}),定义一个操作,记做(con(a,i)),意思是用(a_i-a_{i+1})替代(a_i,a_{i+1}),显然最后一个数字不能进行这样的操作,序列也最多只能进行n-1次操作,而且最后序列会剩下一个数字,求它刚好为t的操作方案,(1 <= N <= 100,1 <= ai <= 100)

    显然,当前的模型是不能进行递推的,因为序列长度在改变,于是有以下性质


    性质1

    假设序列为({a,b,c}),进行操作大概如此

    a b c
    a-b c
    a-b-c
    
    a b c
    a b-c
    a-b+c
    

    于是我们发现所谓的操作,也就是给序列的各个数字前添上+,-号,不难发现第一个数字前必然是+,第2个数字必然是-,问题是不知道后面的+,-序列是否合法,不妨猜测它是合法的,但是暂时没办法证明。

    性质2

    如果把替代后的数用括号看成一个整体

    a b c
    a (b-c)
    (a-(b-c))
    

    于是发现问题转化为刚开始序列只有第一个数字前面为+,后面的全为-,要添上括号,并保证每一个数都被扩到(也就是碰到括号边界),而我们的加减序列,只是被去掉了括号,这条性质是便于理解。

    性质3

    性质1留下一个疑问,就是怎样的+,-序列才是合法的,既然不知道,猜测无论如何都是合法的,首先能够发现的是一个加减序列为(a-b-c-d),即第一个+,后面全是-,我们一定能够不停地对第一个数进行操作使之合法,对于只有两个数一定第二个数符号为-才是让这两个数被加上括号,因此关键在+

    于是对于一个+,-序列而言,遇到+,我们肯定要想办法变为-,而要使之为-,必然前面要有-,让之变为-,于是对于一段连续的+,我们都可以进行这样的操作,而注意到第二个数一定有一个-,因此无论如何后面有+的数总会有-,因此后面无论+-情况如何,总能成为一个合法的操作序列。

    而且也告诉我们,成为操作序列的办法是,遇加变减即可。


    有了这三条性质,我们注意到数字很小,现在问题是该数字是选+还是-,让之最后结果正好为t,于是可以暴力压维保存t,因为并没有求最优性问题,递推数组可以顺便保存方案,1表示这里选+,-1表示这里选-,因此设(f[i][j])表示前i个数权值正好为j的i的符号(0表示这是非法状态),用顺转移有

    (if(f[i][j]))

    [f[i+1][j+a_i]=1,f[i+1][f-a_i]=-1 ]

    边界:(f[1][a_1]=1,f[2][a_2]=-1)

    答案:(f[n][t])

    参考代码:

    #include <iostream>
    #include <cstdio>
    #define il inline
    #define ri register
    #define zero 10000
    using namespace std;
    int a[101],dp[101][20010],
        ans[101];
    void getans(int,int);
    int main(){
        int n,t;scanf("%d%d",&n,&t);
        for(int i(1);i<=n;++i)scanf("%d",&a[i]);
        dp[1][zero+a[1]]=1,dp[2][zero+a[1]-a[2]]=-1;
        for(int i(2),j;i<n;++i)
            for(j=0;j<=20000;++j)
                if(dp[i][j])
                    dp[i+1][j+a[i+1]]=1,
                        dp[i+1][j-a[i+1]]=-1;
        getans(n,t+zero);int tot(2);
        for(int i(2);i<=n;++i){
            while(ans[i+1]==1&&i<=n)++i,printf("%d
    ",tot);++tot;
        }--tot;while(--tot)puts("1");
        return 0;
    }
    void getans(int a,int b){
        if(!a)return;ans[a]=dp[a][b];
        getans(a-1,b-dp[a][b]*::a[a]);
    }
    
  • 相关阅读:
    ScrollVIEW 2000个ITEM不会卡
    嵌套ScrollView 左右滑动不影响上下滑动
    初学数据结构——栈和队列
    初学数据结构——单向循环链表和双向循环链表。
    初学数据结构——单链表
    bootstrap模态框垂直居中
    Javascript经典实例
    Javascript经典实例
    读书笔记-前言
    web中的中文字体的英文名称
  • 原文地址:https://www.cnblogs.com/a1b3c7d9/p/10995805.html
Copyright © 2020-2023  润新知