Music Problem

题意:

传送门
一个类似的题

分析:

  最开始想到的是鸽巢原理,即当 \(n\geq 3600\) 时,必定存在一段连续的数之和为 \(3600\) 的倍数。但是当 \(n<3600\) 时,就不知道怎么处理了。
  看了别人的代码,才发现是 \(dp\)。另外发现还有一种做法,借助 \(bitset\) 来枚举,判断哪些数是可以得到的,\(bt[i]\) 表示 \(i\) 可以得到。
  对于当前枚举到的数 \(a[i]\),如果直接枚举其他数,来得到新的数,复杂度就会比较高。
这时,采用 \(bitset\),借助位移来直接处理。
\(bt<<a[i]\) 表示所有数同时加上 \(a[i]\) 所得到的数,但可能会溢出 \(3600\) 的范围,所以要用 \(bt>>(3600-a[i])\) 来表示,最后两者相或,统计结果,然后或到 \(bt\) 上。接着把 \(bt[a[i]]\)\(1\)

代码:

#include <bits/stdc++.h>
using namespace std;
const int N=3605;
const int maxn=1e5+5;
bitset<N>bt;
int a[maxn];
int main()
{
    int t,n;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        bt.reset();
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            a[i]%=3600;
        }
        if(n>=3600)
            printf("YES\n");
        else
        {
            for(int i=1;i<=n;i++)
            {
                bt|=((bt<<a[i])|(bt>>(3600-a[i])));
                bt[a[i]]=1;
            }
            if(bt[0])
                printf("YES\n");
            else
                printf("NO\n");
        }
    }
    return 0;
}

posted @ 2020-04-14 23:06  xzx9  阅读(129)  评论(0编辑  收藏  举报