AcWing 316. 减操作 线性dp

//f[i,cnt] 表示前i个数字和为cnt 
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=110,M=200020;
int hh=10000;//hh是我们的下标偏移量 
int n,t,f[N][M],a[N],ans[N];
void solve()
{
    f[1][a[1]+hh]=1;//a[1]必然是正数
    f[2][a[1]-a[2]+hh]=-1;//a[2]必然是
    for(int i=3;i<=n;i++)
        for(int j=-10000+hh;j<=10000+hh;j++)
            //前i-1个数字可以组成的和,判断是否可以进行状态转移 
            if(f[i-1][j])
            {
                f[i][a[i]+j]=1;//表示第i个数字前为+号,就说明在这一位进行了减操作 
                f[i][j-a[i]]=-1;//表示第i个数字前为-号,就说明在i-1位进行了减操作 
            }

    int s=hh+t;
    for(int i=n;i>=2;i--)//回溯,确定+-号 
    {
        //判断第i个数字前的符号  
        ans[i]=f[i][s];
        //如果为1,那么就是+的 
        if(ans[i]==1)
            s-=a[i];
        else if(ans[i]==-1)
            s+=a[i];
    }
    //如果这一位为1,那么就说明在前一位进行cut操作
    //那么前一位前一位的前一位再进行时,就会变成+号 
    int cnt=0;
    for(int i=2;i<=n;i++)
        if(ans[i]==1)
        {
            cout<<i-cnt-1<<endl;
            cnt++;
        }
    //如果是-1,那么就说明在1这一位进行了操作 
    for(int i=2;i<=n;i++)
        if(ans[i]==-1)
            cout<<1<<endl;
}
int main()
{
    cin>>n>>t;
    for(int i=1;i<=n;i++)
        cin>>a[i];
    solve();
    return 0;
} 

posted @ 2020-03-31 13:18  晴屿  阅读(109)  评论(0编辑  收藏  举报