思路

简单瞎搞题就瞎搞就好了
看到这题我是想dp的,很明显 dp[ i ]表示 能不能加到i这个值
状态转移方程就是

    dp[0] = true;
    for(int i = 0 ; i < n ; ++i){
        srt<int> q;
        for(int j = l[i] ; j <= r[i] ; ++j){
                int tmp = j*j;
            for(int k = tmp ; k <= maxn ; ++k){
                if(dp[k - tmp]) q.insert(k);//用一个变量存前i个数能到达的位置,防止多计算
            }
        }
        auto it = q.begin();
        while(it != q.end()){
            dp[*it] = true;
            ++it;
        }
    }

代码很好理解我就不多说了
来算算复杂度吧,maxn的最大值是 n * r[i]^2 = 100 * 100 * 100 = 1e6
所以总的复杂度就是1e6 * 100 * 100 = 1e10肯定是超时的。

那肯定是要换一种办法,因为这里知道dp只有两种状态,0 or 1 一般情况这种单一状态状态压缩动态规划的可以通过STL中的bitset去优化。
比如 11001 表示 1 4 5 可以用加法得到,因为 位置1 4 5上的数为1
总结一下,bitset的第X位为1表示整数X可以通过加法得到。
同时这里需要一个额外的变量保存上一个xi加完后能到达的值,不然会出现一些不能到达的值。

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

inline ll read(){
    ll s = 0, w = 1; char ch = getchar();
    while (ch < 48 || ch > 57) { if (ch == '-') w = -1; ch = getchar(); }
    while (ch >= 48 && ch <= 57) s = (s << 1) + (s << 3) + (ch ^ 48), ch = getchar();
    return s * w;
}
bitset<1000005>q,tmp;
int main(){
    int n = read();
    int l = read(),r = read();
    for(int i = l ; i <= r ; ++i) q[i*i]=1;
    while(--n){
        l = read();r = read();
        tmp.reset();
        for(int i = l; i <= r; ++i) tmp |= q<<(i*i);
        q = tmp;
    }
    int ans = 0;
    for(int i = 1; i <= 1000000;i++)
        if(q[i]) ++ans;
    printf("%d\n",ans);
    return 0;
}