HDU

来源:互联网 发布:nike手机抢购软件 编辑:程序博客网 时间:2024/06/04 23:30

题目大意:

给你 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;    }}
原创粉丝点击