一.闲话
做题历程:点开题目->发现做过->点击提交->AC (/x)
二.题解
明显的一道bitset的题目/x
bitset是个高级的黑科技,支持各种操作,其中最有用处的,就是bitset支持位运算。
我曾经尝试模拟了一下,貌似挺简单的,就是开个int数组,值就是当前状态状压后的值,进位就是把值传个下一个下标,直接模拟即可。
如果使用long long模拟的话,可以做到单次操作,不过不知道bitset还有没有其它玄学操作。。。
来看这道题。
我们把一个bitset看做一个支持位运算的bool数组
那么,我们设s[i]表示我们是否可以做到和为i
如果,我们求出来了之前的所有数可以做出来的各种和,现在有个数x,我们把x放进去后,可以做出的和是多少?
我们想想,如果原来我们s[i]=1,即我们原来的集合中可以做出和为i,那么,加入x后,我们是不是就可以做出i+x了?
那么,我们把对于原来数组中所有值为1的下标i,我们把i+x再赋为1就好了
于是,我们想到了左移这个位运算,我们将s这个数组的所有值左移x位,就可以做出来上面的了,但是,需要注意的是,我们不一定非要加入x,我们可能加入的是x+1..x+k各个数,也就是说,我们应该将所有情况的bitset取或。
知道这个操作后,剩下的直接模拟即可
需要注意的是,bitset的位运算的复杂度为:
(n为bitset的大小)
所以总复杂度为:,可以通过此题。(当然,你用long long/unsigned long long模拟一个bitset,复杂度会小一半)
代码:
#include<bits/stdc++.h> using namespace std; bitset<1000001>s,p; int main(){ int n; s[0]=1; scanf("%d",&n); for(int i=1;i<=n;++i){ int l,r; scanf("%d%d",&l,&r); p.reset();//清空p for(int j=l;j<=r;++j){ p|=(s<<(j*j)); } s=p; } cout<<s.count();//输出bitset里面1的个数 return 0; }
下面是模拟bitset代码(复杂度小了一倍,但常数挺大的所以跑得并没有想象中的快qwq)
代码:
#include<bits/stdc++.h> using namespace std; const int N=15628,block=64; unsigned long long w[block];//截位 struct my_bitset{ unsigned long long a[N];unsigned int maxe;//maxe,当前最大有值块的编号,加速用 inline void reset(){ for(unsigned int i=0;i<=maxe;++i){ a[i]=0; } maxe=0; } inline unsigned int count(){//直接暴力就行 unsigned int res=0; for(unsigned int i=0;i<=maxe;++i){ for(unsigned int j=0;j<block;++j){ res+=((a[i]>>j)&1); } } return res; } }s,p; inline my_bitset operator<<(my_bitset x,unsigned int y){ unsigned int k=(y/block);y&=63; //大移动 if(k){ for(int i=x.maxe;~i;--i){ x.a[i+k]=x.a[i]; } for(int i=k-1;~i;--i){ x.a[i]=0; } x.maxe+=k; } //小移动 for(int i=x.maxe;~i;--i){ unsigned long long v=(x.a[i]&w[y]); x.a[i]<<=y;v>>=(block-y);x.a[i+1]|=v;//faster move } if(x.maxe+1<N&&x.a[x.maxe+1]){ ++x.maxe; } return x; } inline void operator|=(my_bitset &x,my_bitset y){ x.maxe=max(x.maxe,y.maxe); for(int i=x.maxe;~i;--i){ x.a[i]|=y.a[i]; } return; } int main(){ unsigned long long k=1; for(unsigned int i=1;i<block;++i){ k<<=1; } for(unsigned int i=1;i<block;++i){ w[i]=(w[i-1]>>1)|k; } unsigned int n; s.a[0]=1;s.maxe=0; scanf("%d",&n); while(n--){ unsigned int l,r; scanf("%d%d",&l,&r); p.reset(); for(unsigned int j=l;j<=r;++j){ p|=(s<<(j*j)); } s=p; } cout<<s.count(); return 0; }