hdu 6140 Hybrid Crystals 阅读题 OR bitset 优化01背包

来源:互联网 发布:高清网络光端机 编辑:程序博客网 时间:2024/06/12 19:32

题目连接


题意:

确实比较坑,题中给出的信息保证了凑出的数连续,


但是我一直以为没什么用也没发现这个....


update:

http://blog.csdn.net/howardemily/article/details/77367390


做完这两个题我突然感觉对这个题目为什么一定保证是连续的有了新的感觉啊,并不知道自己理解的对否. 假设我们先只考虑L 的情况,那么所有的N也都看成L的话,那么当前可以凑出的最大的和为 sum(ai) (bi==N||bi==L) 那么此时新加入进来的ai 满足了 ai<=sum 的情况,根据上面我做的两题 只要满足 sum+1>=ai 即可证明是连续的,所以这里的话如果全为正数那么凑出来的一定是一个连续的区间范围.那么全为正数区间右端点就是可以凑出做大的k.

只考虑负数的情况也同理,那么从而可以确定了能凑出的区间范围,直接判断k在里面就好了/


然后就发现01背包肯定T了啊,那我就bitset优化一下吧.第一次写bitset,没办法 xjb搞搞吧,然后就一直T.

这里bitset优化的时间复杂度大致是n*k/64  或者/32 吧 这个不太清楚.

如果这个是个搜索我肯定就想到了这种剪枝...但是没想到...这样优化的常数是巨大的.

就是当所有负数加起来的和 大于k,或者所有正数加起来的和小于k.那么肯定就凑不出来了啊...这时候就不需要去跑背包了,节省了常数...

另外我把所有N,都double了一下...这种方法不太提倡吧,毕竟不是正解。。。

#include <iostream>#include <cstring>#include <cstdio>#include <algorithm>#include <bitset>using namespace std;const int maxn = 2e6 + 7 ;const int maxm = 2e3 + 7;int a[maxm], num[maxm];bitset<maxn> dp;char b;inline int read(){    int x=0,f=1;char ch = getchar();    for(;ch<'0'||'9'<ch;ch=getchar())if(ch=='-') f=-1;    for(;'0'<=ch&&ch<='9';ch=getchar())x=(x<<3)+(x<<1)+ch-'0';    return x*f;}int main(){    int n, k, t;    scanf("%d", &t);    while(t--)    {        dp.reset();        scanf("%d%d", &n, &k);        // k += maxm;        for(int i = 1; i <= n; i++)            a[i] = read();        int tot = 1;        for(int i = 1; i <= n; i++)        {            scanf(" %c", &b);            if(b == 'L')                num[tot++] = a[i];// num[tot-1] += maxm;            else if(b == 'D')                num[tot++] = -a[i];//num[tot-1] += maxm;            else            {                num[tot++] = a[i];// num[tot-1] += maxm;                num[tot++] = -a[i];//num[tot-1] += maxm;            }        }        int sum1=0,sum2=0;          for(int i=1;i < tot;++i){              if(num[i] < 0) sum2 += num[i];              if(num[i] > 0) sum1 += num[i];          }                                  if(sum2>k||sum1<k) //最最重要的剪枝         {        puts("no");        continue;        }k += 1e6;dp.set(1e6);        for(int i = 1; i < tot; i++)        {            if(dp.test(k))//一点小优化, 无影响.             break;            if(num[i] > 0)            {                dp |= (dp << num[i]);            }            else            {                num[i] = -num[i];                dp |= (dp >> num[i]);            }        }        //k += 1e6;        if(dp.test(k))            puts("yes");        else        {            puts("no");        }    }    return 0;}



知道是连续的好简单啊,以后我算是知道了,超过200+人过的都是水题,我大胆的猜结论蒙吧...还sb带着队友想优化 哈哈

#include<bits/stdc++.h>using namespace std;const int maxn = 1e3+10;int a[maxn];char b[maxn][2];int n,k;int main(){int _;cin>>_;while(_--){cin >> n >> k;for(int i = 1;i <= n;i++)scanf("%d",&a[i]);for(int i = 1;i <= n;i++)scanf("%s",b[i]);int l = 0,r = 0;for(int i = 1;i <= n;i++){if(b[i][0] != 'L')l -= a[i];if(b[i][0] != 'D')r += a[i];}if(l <= k && k <= r)puts("yes");elseputs("no");}return 0;} 



原创粉丝点击