题目大意:

给你 n 个数(1000),每个数 0<=a[ i ]<=1000,对于每个数,它有一个 b[i] 与它对应,b[ i ] 有三种值:D、L、N,分别表示 a[ i ] 只能取负,只能取正,既能取负又能取正。现在给你一个整数 k ,问你是否可以从 a 中选取若干个,使得它们的和正好等于 k 。并且告诉你 a 数组的一个限制:每一个 a[i] 都小于等于之前所有 a 的选取组合的最大值,且大于等于最小值。并且要求:a[1]=1;b[1]=N;

分析:

猜想:

对于给你的一串数 a[1]~a[i] 假设它们能组成的最大值为 max ,最小值为 min ,那么,对于区间 [ min , max ] 中的任意一个数 t ,我都有 a 中的一种选取方式使得这些数之和等于 t 。

下面我选择第一数学归纳法证明:

首先,对于i等于1,猜想显然成立;

其次,假设对于某一整数 i ,猜想成立。那么对于 i+1 ,因为 a[ i ] 小于等于之前所有数能取得的最大和 max ,并且大于等于之前所有数能取到的最小和 min 。那么显然 a[ i ] 就落到了区间 [ min , max ] 里面,那么区间 [ a[ i ] , a[ i ]+max ] 之间的每一个数也都可以通过 [ 0 , max ] 之间的每一个组合加上 a[ i ] 得到(只是对于 b[ i ]=L 的情况来说)。其他两种 b 的取值同理。所以 i+1 猜想同样成立。

证毕~

代码:

#include<bits/stdc++.h>
using namespace std;

int t,n,k,a[1050],maxx,minx;
char c;
int main()
{
    scanf("%d",&t);
    while(t--)
    {
        maxx=0;minx=0;
        scanf("%d%d",&n,&k);
        //cout<<n<<k<<endl;
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
        } //cout<<n<<k;
        for(int i=1;i<=n;i++)
        {
           // while(1)

                scanf("%c",&c);
                while(c==' ' || c=='\n')scanf("%c",&c);
                if(c=='D')minx-=a[i];
                else if(c=='L')maxx+=a[i];
                else
                {
                    maxx+=a[i];
                    minx-=a[i];
                }

        }
        if(k>=minx&&k<=maxx)cout<<"yes"<<endl;
        else cout<<"no"<<endl;
    }

}