题目大意:
给你 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);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
for(int i=1;i<=n;i++)
{
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;
}
}