题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6140
题目意思是给出n个水晶,水晶有三种,一种是中性水晶,它可以提供正能量也可以提供负能量。
光明水晶,只能提供正能量,黑暗水晶只提供负能量。然后给出k,询问这些水晶可否组成k。
原来看了题目题解了,就觉得题解不对。
后来我发现了,不是题解不对,也不是题不对,是自己没好好读题,刚开始读题的时候,觉得英文
太长了,然后发现英文最后一段说,如果你觉得上面太复杂的话,可以看下面的式子,下面的式子
的意思就是从这些水晶中挑选一些,然后看是否组成k,然后在看题解感觉不对啊。后来我才发现
最后一段根本就不是对前面题意的概括,倒数第二个长的公式才是关键。
ai≤∑j=1i−1aj[bj=N]+∑j=1i−1aj[bi=L∩bj=L]+∑j=1i−1aj[bi=D∩bj=D](2≤i≤n).
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; }