https://ac.nowcoder.com/acm/contest/331/H

题目可以理解为有n(5000)个物品,每个物品有价值a[i](1~1e9),从中选择最少的物品,使得剩余物品的价值之和小于固定的值K(1~1e15),求解决方案,如果有多个解决方案,则用1表示选择该物品,0表示未选择,组成一个长度为n的01串,给出字典序最小的串

刚开是看题目,知道是背包问题了,然而呢,然而接下来怎么做就完全不知道了。

看了看题解,

首先,可以求出来最少选择多少个物品,对的,直接选价值最大的物品就行了,得到物品数ans

这个ans非常有用,接下来的过程就要好好利用到ans,于是问题就变成了,找到解决方案,该解决方案使用ans个物品,且为选择的物品价值总和不超过K

定义dp[i][j]为使用在[i~n]个物品中选择[j]个物品,剩余物品的最小价值数

可以通过简单的dp算出dp[i][j]=min(dp[i+1][j]+a[i],dp[i+1][j-1])

于是我们可以这样想,从左到右扫描每个物品,能不选择该物品的时候我们就不选择该物品,这不也就是字典序最小的精髓么,能是0就是0,不得已就是1。

我们记录开始的价值和为C=0,开始选择了cnt=0个物品

如果前面i个物品选择cnt个的剩余价值和C+后面[i+1,n]的物品选择(ans-cnt)个的剩余价值和dp[i+1,ans-cnt] >K

那么第i个物品就非选择不可,

否则第i个物品就可以不选,那我们就不选

//Problem:
//Date:
//Skill:8_2-框架
//Bug:
/////////////////////////////////////////definations////////////////////
#define CLR(a) memset((a),0,sizeof(a))
#define RE(i,n)  for(ll i=0;i<n;i++)
#define RE2(i,n) for(int i=1;i<=n;i++)
#define IN(n) scanf("%d",&n)
#define LLIN(n) scanf("%lld",&n)
#define INC(c) do {scanf("%c",&c);}while(isspace(c))
#define PI(a) prllf("%d",a)
#define LLPI(a) prllf("%lld",a)
#define PN  puts("");
#include<string.h>
#include<math.h>
#include<vector>
#include<map>
#include<algorithm>
using namespace std;
const long long llinf = 0x3f3f3f3f3f3f3f3f;
const int inf = 0x3f3f3f3f;
 
#define CPP_I/O
#include<iostream>
#include<iomanip>
#include<string>
#include<stdio.h>
///////////////////////////////////////////////////////////////////////////////////
 
////////////////////////////////////////options////////////////////////////////
typedef long long ll;
const ll maxn = ll(5e3+4);
ll n,k;
ll a[maxn],b[maxn];
ll dp[maxn][maxn];
//ll num(0);
ll num(0),sum=0;
bool ans[maxn];
//#define LOCAL
///////////////////////////////////////////////////////////////////////////////
int main()
{
#ifdef LOCAL
 
//  freopen("C:\\Users\\VULCAN\\Desktop\\data.in", "r", stdin);
#endif
    //How to think:
    //先认真读题,把题目逻辑化,读清全部条件,再做,不然,哼哼
    //1.分治 2.容斥 3.化多元为单元
    //4.dp 分阶段,后阶段受前阶段的影响
    //5.凡是有很大的指数的,都可以先用log算一下
    //6.预处理,作用非常大,很快
    //
    //1.Do you use cout/cin? Do not use!
    //2.what's the maximum ll data? Is it beyond I32d?
    //3.Ever Mod after neccesary calculation?
    //4.Ever Cleaned the array before using?
    ///////////////////////////////////////////code////////////////////////////////
    ll T(1), times(0);
    //IN(T);
    while (++times,T--)
    {
        cin>>n>>k;num=n;
        RE2(i,n)cin>>a[i],b[i]=a[i];
        sort(b+1,b+1+n);
//      cout<<sum<<' '<<num<<endl;
//      for(ll i=n;i;--i)
        RE2(i,n)
        {
            sum+=b[i];
            if(sum<=k)
            {
                --num;
            }
            else break;
        }
//      cout<<sum<<' '<<num<<endl;
        for(ll i=n;i;--i)
        {
            dp[i][0]=dp[i+1][0]+a[i];
            for(ll j=num;j;--j)
            {  
                dp[i][j]=min(dp[i+1][j]+a[i],dp[i+1][j-1]);
            }
        }
         
        ll C=0,res(num);
        RE2(i,n)
        {
            if(C+a[i]+ dp[i+1][res]>k)
            {
                ans[i]=1;
                --res;
            }
            else
                C+=a[i],ans[i]=0;
        }
        cout<<n-num<<endl;
        RE2(i,n)cout<<ans[i];
        cout<<endl;
    }
    //////////////////////////////////////////////////////////////
    //dividing line
    return 0;
}