题目
题意很简单,就是要你求所有满足x + y + z = k的方案数。
直接一个个枚举的话太慢了,接近1e24。
我们考虑用差分去优化枚举。
怎么优化呢。
我们先来考虑x + y的得数情况,可以枚举x。
x + y的范围一定是在[x,x+b]的,也就是说,对于每个x来说,x + y的得数就是从 x ~ x + b的所有数,也就是这个区间都加上1,用差分来维护。
枚举一遍x之后就能得到一个x + y得数的差分数组,将差分数组做一个前缀和操作就能得到实际的每个得数的个数。
这是第一层差分数组。
之后,同样考虑(x + y)+ z的得数情况。
我们可以枚举 (x + y)。
(x + y)+ z的得数范围是在[x + y, x + y + c]的,但是注意对于每个(x + y)来说,x + y + z的得数就是之前第一层差分求得的 (x + y)的得数个数倍从(x + y)~ (x + y)+ c 的所有数,同样用差分来维护。
这是第二层差分数组。
然后将这个第二层的差分数组求前缀和,就能得到x + y + z的所有得数分别有多少个,这是最终的得数个数数组。
最后我们需要的答案就是遍历最终得数个数数组,将得数为 0 ~ d的所有个数加起来。
注意数据需要开long long。
#include<bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f
#define endl '\n'
#define IOS std::ios::sync_with_stdio(false),cin.tie(0), cout.tie(0)
using namespace std;
const int N = 6e6 + 10;
int a, b, c, d;
ll ans;
ll xy[N],xyz[N];
int main()
{
IOS;
cin >> a >> b >> c >> d;
for(int i = 0; i <= a; i ++) //枚举a,+ b的所有情况。
{
xy[i] ++;
xy[i + b + 1] --; //i + y范围是从i 到 i + b 都有
//一次,所以将这个范围都+1.
}
for(int i = 1; i <= a + b; i ++) //得到x + y得数个数
xy[i] += xy[i - 1];
for(int i = 0; i <= a + b; i ++)
{
// i + z范围是从i 到 i + c 都有
// xy[i]次,所以将这个范围都+ xy[i]。
xyz[i] += xy[i];
xyz[i + c + 1] -= xy[i];
}
for(int i = 1; i <= a + b + c; i ++) //得到x+y+z得数个数
xyz[i] += xyz[i - 1];
for(int i = 0; i <= d; i ++)
ans += xyz[i]; //找到所有x+y+z == k 的
//得数个数,并加进答案
cout << ans << endl;
return 0;
}