这个题目还有点意思。。。一开始愣是没看懂。。。暴力的做法O(100^100)超时,因为最终要是求得所有不同数的个数,我们考虑用二进制表示这个数能出现或者不能出现。二进制操作有一个非常好用的工具是bitset。如果不会bitset,http://www.cplusplus.com/reference/bitset/bitset/。因为数字最大无非是,
,所以bitset开到1e6就行了,bitset从右边往左边走,它的位置表示十进制位置。感觉说不太清,直接举例子吧。
如果输入
2
1 2
1 2
先考虑,我们有
,
看一下二进制是如何操作的。
给定表示
二进制串向左移动
个位置,这个位置刚好就是i所对应的十进制数,一开始设
,表示答案串最后一位为1没有实际意义就是为了后面的操作。然后
,这个时候字符串下标1的位置字符串0变1(|有1则1),然后
,这个时候字符串4的位置0变1,看到这里应该明白了,01二进制串第
为
表示这个数不会出现,为
表示这个数出现,并且下标就是对应这个数的值。我们再来考虑
,看它是怎么累加的。
结束后我们要保存这个结果串
,然后继续遍历
,这个时候
,s1已经是上一个区间数的串了,在这个基础上继续左移,
,当
有
注意到,表示的就是
(对应下标看)。然后还有
,就是最后一个串,因为我们只要求出现一次的数,出现多次的会被
运算覆盖掉,然后不断迭代,最后答案串的
的个数就是
的种类数。
代码:
#include<iostream> #include<bitset> using namespace std; const int maxn = 1100000 ; void solved(){ int n;cin>>n; bitset<maxn>s1,s2; s1.set(0); while(n--){ s2.reset(); int l,r;cin>>l>>r; for(int i = l ; i <= r; i++){ s2 |= s1 << (i * i); } s1 = s2; } cout<<(int)s1.count()<<endl; } int main(){ solved(); return 0; }