Enigmatic Partition
题目描述:
数字
的分区是所有数字之和等于
的集合。
如果分区
满足以下签名,则称为神秘分区:
- 是整数, ,并且
- 表示 ,并且
令 为 的神秘分区的数量。 给定 和 ,请计算
输入描述:
第一行包含测试用例的数量
。
在下面的每条
行中,都有两个整数
和
。
输出描述:
对于每个测试用例,输出一行包含 # : 的行,其中x是测试用例编号,y是答案。
样例输入:
3
5 7
7 9
1 9
样例输出:
Case #1: 2
Case #2: 7
Case #3: 8
说明:
f(1) = 0.
f(2) = 0.
f(3) = 0.
f(4) = 0.
f(5) = 0.
f(6) = 1: 6 = 1 + 2 + 3.
f(7) = 1: 7 = 1 + 1 + 2 + 3.
f(8) = 2: 8 = 1 + 1+ 1 + 2 + 3, 8 = 1 + 2 + 2 + 3.
f(9) = 4: 9 = 1 + 1 + 1 + 1 + 2 + 3, 9 = 1 + 1 + 2 + 2 + 3, 9 = 1 + 2 + 3 + 3, 9 = 2 + 3 + 4
思路:
考虑差分。
首先,我们观察题目所给的
的条件:首项末项相差为二,且相邻数字的差值最多为
的不下降序列。
所以对于每一个这样的序列我们都可以分成三段:
根据题目意思,我们可以列出下面的等式:
这里我们可以发现,对于每一个
都可以分成
个未知数:
,其中
想到这里,我们就要引入解这题的重要方法————差分
差分用来求解区间加减求和的问题。
实现:对于每一个区间,我们在差分数组上对这个区间的第一个位置加上修改值,最后一个位置减去修改值,再对差分数组求前缀和,那么这个得到的前缀和数组就是最后经过修改的数组。
简单来说,设原数组是
,差分数组是
,那么
对于差分,还有两个变式:
- 二阶差分
二阶差分其实就是差分里再套一个差分,假设要减去或加上一段有规律的数字,可以对差分数组再进行差分,得到一个二阶差分数组,就可以把有规律的转化成同样的数值。
- 隔项差分
隔项差分就是隔一项差分一次。
介绍完差分,回到本题:
刚刚我们推出了:
所以我们只要枚举
和
的值,在区间首尾进行标记,最后变回原来的数组就可以了
:
#include<bits/stdc++.h>
#define ll long long
const int MAXN=1e5+10;
ll t,l,r,qian[MAXN<<1],f[MAXN<<2];
int main(){
for(int i=3;i<MAXN;++i)
for(int j=i;j<MAXN;j+=i){
f[j+3]++;
f[j+2*i]++;
f[j+i+1]--;
f[j+i+2]--;
}
for(int i=3;i<MAXN;++i) f[i]+=f[i-2];
for(int i=1;i<MAXN;++i){
f[i]+=f[i-1];
qian[i]=qian[i-1]+f[i];
}
scanf("%lld",&t);
for(int Case=1;Case<=t;Case++){
scanf("%lld%lld",&l,&r);
printf("Case #%d: %lld\n",Case,qian[r]-qian[l-1]);
}
}