2017多校八 1008题 hdu 6140 Hybrid Crystals 推理

来源:互联网 发布:linux 监听udp端口 编辑:程序博客网 时间:2024/06/06 14:23

转载地址:2017多校八 1008题 hdu 6140 Hybrid Crystals 推理

题意

给定 n (1n103) 个非负整数,有些系数为 1 ,有些为 1,有些可为 1 可为 1,要求选取其中的一个子集,使得和为 k (|k|106). 
此外,这 n 个数还满足一些特殊条件: 
1. a1=1,其系数可正可负 
2.

aij=1i1aj[bj=N]+j=1i1aj[bi=Lbj=L]+j=1i1aj[bi=Dbj=D](2in).

玄学?非也

比赛时破罐子破摔直接判断 k 在不在左右两个端点范围内,竟然就过了,然而这是为什么呢?

结论

这道题中的数能组成的数构成了一个连续区间.

证明

关注一下上面的两个条件,由条件 1a[1] 结束后可以连续(即区间内每一个元素均可)取到的范围为 [1,1]
不妨设处理到第 i 个元素结束时可以连续取到的范围为 [Lo,Hi], 显然有

Lo=(bj=Njiaj+bj=Daj),Hi=bj=Njiaj+bj=Laj.

1. 假设第 i+1个元素的属性为 L
则根据条件 2aiij=1aj[bj=N]+ij=1aj[bj=L]=Hi,即 aiHi, 
[0,Hi]+ai=[ai,Hi+ai],有aiHi,故 [Hi,Hi+ai][ai,Hi+ai], 
原范围  新范围即为 [Lo,Hi][Hi,Hi+ai]=[Lo,Hi+ai],且连续 
2. 假设第 i+1个元素的属性为 D
与上同理 
3. 假设第 i+1个元素的属性为 N
则根据条件 2aiij=1aj[bj=N]Hi,aiij=1aj[bj=N]Lo, 亦与上同理. 
由数学归纳法得:这道题中的数能组成的数构成了一个连续区间.

所以上面的玄学做法(大雾)就是有理有据的了

下面几个AC代码,那个看懂看哪个

#include <queue>#include <iostream>#include <stdio.h>#include <stdlib.h>#include <string>#include <string.h>#include <vector>#include <map>#include <assert.h>#include <algorithm>using namespace std;#define debug printf("%s %d\n", __FUNCTION__, __LINE__)const int maxn = 1e3 + 10;int a[maxn];char b[maxn];int main(int argc, char **argv) {    ios_base::sync_with_stdio(false);    int cases;    cin >> cases;    while (cases--) {        int n;        long long k;        cin >> n >> k;        for (int i = 1; i <= n; i++) cin >> a[i];        for (int i = 1; i <= n; i++) cin >> b[i];        assert(a[1] == 1);        assert(b[1] == 'N');        long long uplimit = 1, downlimit = -1;        long long exactlimit = 1;        for (int i = 2; i <= n; i++) {            //cout << i << ' ' << a[i] << ' ' << b[i] << endl;            //cout << uplimit << ' ' << downlimit << endl;            assert(a[i] >= 0 && a[i] <= 1000);            if (b[i] == 'N') {                assert(a[i] <= exactlimit);                uplimit += a[i], downlimit -= a[i];                exactlimit += a[i];            }            if (b[i] == 'L') {                assert(a[i] <= uplimit);                uplimit += a[i];            }            if (b[i] == 'D') {                assert(a[i] <= -downlimit);                downlimit -= a[i];            }        }        if (k >= downlimit && k <= uplimit) printf("yes\n");        else printf("no\n");    }    return 0;}
这个代码感觉后面判断K的时候可以写的简单点的
#include <iostream>using namespace std;const int MAXN = 1111;int n, k;int A[MAXN];int main(){    int T;    scanf("%d", &T);    while (T--)    {        scanf("%d%d", &n, &k);        int tmp1 = 0, tmp2 = 0;        for (int i = 1; i <= n; i++)        {            scanf("%d", &A[i]);        }        char ch;        for (int i = 1; i <= n; i++)        {            scanf("%c%c", &ch, &ch);            if (ch == 'N')            {                tmp1 += A[i];                tmp2 -= A[i];            }            else if (ch == 'L')            {                tmp1 += A[i];            }            else            {                tmp2 -= A[i];            }        }        if (k > 0)         {            if (tmp1 >= k)            {                printf("yes\n");            }            else            {                printf("no\n");            }        }        else if (k < 0)        {            if (tmp2 <= k)            {                printf("yes\n");            }            else            {                printf("no\n");            }        }        else        {            printf("yes\n");        }    }    return 0;}


原创粉丝点击