一.闲话
做题历程:点开题目->发现做过->点击提交->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;
} 
京公网安备 11010502036488号