2020暑期牛客多校训练营第八场(E)Enigmatic Partition(数学,二阶隔项差分)

Enigmatic Partition

原题请看这里

题目描述:

数字 n n 的分区是所有数字之和等于 n n 的集合。
如果分区 n = a 1 + a 2 + . . . + a m n = a_1 + a_2 + ... + a_m 满足以下签名,则称为神秘分区:

  • a i a_i 是整数, 1 a i n 1 \le a_i \le n f o r for 1 i m 1 \leq i \leq m ,并且
  • a i a i + 1 a i + 1 a_i \leq a_{i + 1} \leq a_i + 1 表示 1 i m 1 \leq i \leq m ,并且
  • a m = a 1 + 2 a_m = a_1 + 2

f ( n ) f(n) n n 的神秘分区的数量。 给定 l l r r ,请计算 i = l r f ( i ) \sum_ {i = l} ^ r f(i)

输入描述:

第一行包含测试用例的数量 T ( 1 T 10 , 000 ) T(1 \le T \le 10,000)
在下面的每条 T T 行中,都有两个整数 l l r ( 1 l r 100 , 000 ) r(1 \le l \le r \le 100,000)

输出描述:

对于每个测试用例,输出一行包含 C a s e Case # x x y y 的行,其中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

思路:

考虑差分。
首先,我们观察题目所给的 f ( n ) f(n) 的条件:首项末项相差为二,且相邻数字的差值最多为 1 1 的不下降序列。
所以对于每一个这样的序列我们都可以分成三段:
在这里插入图片描述

  • a 1 + a 2 + a 3 = m a_1+a_2+a_3=m
  • a 1 a 2 a 3 1 a_1,a_2,a_3 \ge 1

根据题目意思,我们可以列出下面的等式:

  • a 1 v a l + a 2 ( v a l + 1 ) + a 3 ( v a l + 2 ) a_1val+a_2(val+1)+a_3(val+2)
  • = a 1 v a l + a 2 v a l + a 2 + a 3 v a l + 2 a 3 =a_1val+a_2val+a_2+a_3val+2a_3
  • = v a l ( a 1 + a 2 + a 3 ) + a 2 + 2 a 3 =val(a_1+a_2+a_3)+a_2+2a_3
  • = v a l m + a 2 + 2 a 3 =valm+a_2+2a_3
  • = n =n

这里我们可以发现,对于每一个 n n 都可以分成 4 4 个未知数: v a l , m , a 2 , a 3 val,m,a_2,a_3 ,其中 a 2 , a 3 1 a_2,a_3 \ge 1
想到这里,我们就要引入解这题的重要方法————差分

差分用来求解区间加减求和的问题。
实现:对于每一个区间,我们在差分数组上对这个区间的第一个位置加上修改值,最后一个位置减去修改值,再对差分数组求前缀和,那么这个得到的前缀和数组就是最后经过修改的数组。
简单来说,设原数组是 a [ ] a[] ,差分数组是 b [ ] b[] ,那么 a i = b i b i 1 a_i=b_i-b_{i-1}
对于差分,还有两个变式:

  • 二阶差分

二阶差分其实就是差分里再套一个差分,假设要减去或加上一段有规律的数字,可以对差分数组再进行差分,得到一个二阶差分数组,就可以把有规律的转化成同样的数值。

  • 隔项差分

隔项差分就是隔一项差分一次。
介绍完差分,回到本题:
刚刚我们推出了:
v a l m + a 2 + 2 a 3 = n valm+a_2+2a_3=n
所以我们只要枚举 v a l val m m 的值,在区间首尾进行标记,最后变回原来的数组就可以了

A C AC C o d e Code :

#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]);
	}
}

猜你喜欢

转载自blog.csdn.net/s260127ljy/article/details/107786813