2017 Multi-University Training Contest - Team 8:Hybrid Crystals

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6140

题目意思是给出n个水晶,水晶有三种,一种是中性水晶,它可以提供正能量也可以提供负能量。

光明水晶,只能提供正能量,黑暗水晶只提供负能量。然后给出k,询问这些水晶可否组成k。


原来看了题目题解了,就觉得题解不对。

后来我发现了,不是题解不对,也不是题不对,是自己没好好读题,刚开始读题的时候,觉得英文

太长了,然后发现英文最后一段说,如果你觉得上面太复杂的话,可以看下面的式子,下面的式子

的意思就是从这些水晶中挑选一些,然后看是否组成k,然后在看题解感觉不对啊。后来我才发现

最后一段根本就不是对前面题意的概括,倒数第二个长的公式才是关键。


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


这个公式的意思是,可以分开写。

B[i] = N , a[i] = SUM(a[j]) (B[j] == N,j属于1~i-1)


B[i] = L, a[i] = SUM(a[j])(B[j] == N,j属于1~i-1) + SUM(a[j])(B[j] == L)


B[i] = D,a[i] = SUM(a[j])(B[j] == N,j属于1~i-1) + SUM(a[j]) (B[j] == D)

也就是第i个位置的a[i]取决于它是什么类型的水晶,

如果这个水晶是中性的,那么a[i]的值就可以取i之前所有中性水晶的和sum,之内的数字。

如果这个水晶是L性的,那么a[i]的值就是取i之前所有中兴水晶和L性水晶的能量的和sum之内的数字

如果这个水晶是D性的,那么a[i]的值就是取i之前所有中性水晶和D性水晶的能量的和sum之内的数字。


由于我们知道A[1] = 1  B[1] = N

由上面的条件我们知道,无论第二个水晶是什么类型,A[2] 只会取0,1.

此时我们假如没有中性的水晶。

则第一个L性的水晶,其能量值可以取的值是0,1

则第二个L性的水晶,其能量值可以取的值是0,1,2

则第三个L性的水晶,其能量值可以取的值是0,1,2,3,4

则第四个L性的水晶,其能量值可以取的值是0,1,2,3,4,5,6,7,8.

。。。。。。。。。。。。。。。。。。。。

我们发现上面的组合就能组成0,1,2,~13,14,15这么多种情况。

由于刨去N型水晶后,我们发现这些L性水晶组成的区间是连续的。

则这时我们随变插入N性水晶,对于连续的区间来说,同时加一个数,或减去一个数,其所得到的

新区间还是连续的。

于L性的一样,

则第一个D性的水晶,其能量值可以取的值是0,1

则第二个D性的水晶,其能量值可以取的值是0,1,2

则第三个D性的水晶,其能量值可以取的值是0,1,2,3,4

则第四个D性的水晶,其能量值可以取的值是0,1,2,3,4,5,6,7,8.

其所能组成的值时-15,-14,-13,。。。。。。。,-2,-1,0

区间也是连续的。

所以题目就转化成了,初始区间【-1,1】.当假如一个N性水晶的时候,R+a[i],L-a[i]。

时一个L性水晶的时候,R + a[i],当是一个D性水晶的时候,R-a[i].

所以这个题目就变成大家口中的水题了,比赛时压根没这样想,队友一个用递归写,

一个用DP写,全超时。


AC代码:

#include <iostream>
#include <stdio.h>
#include <stdlib.h>

using namespace std;

const int maxn = 1003;

int a[maxn];
int letter[maxn];
int main()
{
    int t,n,k;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&k);
        for(int i = 1; i <= n; i++)
            scanf("%d",&a[i]);
        int left = 0,right = 0;
        for(int i = 1; i <= n; i++)
        {
            char ch;
            scanf(" %c",&ch);
            if(ch == 'N')
            {
                left = left-a[i];
                right = right+a[i];
            }
            else if(ch == 'L')
            {
                right = right+a[i];
            }
            else
            {
                left = left-a[i];
            }
        }
        if(left<=k && right>=k)
            printf("yes\n");
        else
            printf("no\n");
    }
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值