题目描述

图片说明

输入描述

第一行一个数 n。
然后 n 行,每行两个数表示 i ,i

输出描述

输出一行一个数表示答案。

整体思路

首先对题意进行分析:从n组数据中,每组(i ~i)选一个数进行平方相加,最终记录不同的平方和数量。

如何表示不同的平方和?

我们想到桶排序的方式:若该和存在,就将对应下标位置值1;反之置0。由于每个数只有1,0(存在,不存在)两种情况,可以考虑使用biteset类型。bitset容器可以视为每一种每个元素只占1位的数组,只有当元素值只可能是0或1时才可以使用。

ans[i] = 1代表存在平方和为i;ans[i] = 0代表不存在平方和为i。

如何表示数字相加

通过对ans数组的整体左移可以实现加的功能。eg:0011 表示和可以是1和0;左移一位后 0110 表示和可以是2和1。即:左移多少位就代表在原有的和上加多少。由于最大和可以达到100图片说明 100图片说明 100,所以设置数组大小为100图片说明 100图片说明 100。

左移后得到的新的数组与元素组相或,即可得所有的和的可能性。(若与原数组的某个和相同,由于1 | 1 = 1,或运算后直接可达到去重的效果)。

由于每组数据只取其中的一个数的平方,所以在遍历(i ~i)时需要设置临时数组temp。

完整代码

#include<iostream>
#include<bitset>
#define IOS ios::sync_with_stdio(false);
using namespace std;
const int maxn = 100*100*100+6;
bitset<maxn>ans, temp;
int main()
{
    IOS;
    int n, l, r;
    cin>>n;
    cin>>l>>r;
    for(int i=l; i<=r; i++)
    {
        ans[i*i] = 1;
    }
    for(int i = 2; i <=n; i++) 
    {
        cin>>l>>r;
        temp.reset();
        for(int i=l; i<=r; i++)
        {
            temp |= ans << i*i;
        }
        ans = temp;
    }
    cout<<ans.count()<<endl;
    return 0;
}

总结

通过今天题目的学习,我初步认识了bitset的用法,也接触到了状态压缩数组(用二进制形式表示数组下标的状态)的思想。
另外,学到了ios::sync_with_stdio(false);的用法(简单来说就是减少cin/cout的时间)。
题目最后确定算法思想无误后仍一直出错的原因,是 maxn 定义的太大了,以后要注意对数组容量进行合理估计。