原题
题目描述
样例
输入
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)
f(n)是首尾差等于
2
2
2并且相邻两个差最多为
1
1
1的递增序列。
若设第一段的数值为
a
1
a1
a1,则第二段的数值为
a
+
1
a+1
a+1,第三段的数值为
a
+
2
a+2
a+2。我们再设第一段的长度为
b
1
b1
b1,第二段的长度为
b
2
b2
b2,第三段的长度为
b
3
b3
b3。
则我们可以得出以下结论
:
:
:
- a b 1 + ( a + 1 ) b 2 + ( a + 2 ) b 3 = n ab1+(a+1)b2+(a+2)b3=n ab1+(a+1)b2+(a+2)b3=n
- a ( b 1 + b 2 + b 3 ) + b 2 + 2 b 3 = n a(b1+b2+b3)+b2+2b3=n a(b1+b2+b3)+b2+2b3=n
-
a
m
+
b
2
+
2
b
3
=
n
am+b2+2b3=n
am+b2+2b3=n
然后用两次差分即可。
代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=1e5+5;
ll t,l,r,f,a[maxn<<2],b[maxn<<1];
int main()
{
for(int i=3;i<=1e5;i++)for(int j=i;j<=1e5;j+=i)a[j+3]++,a[j+i+1]--,a[j+i+2]--,a[j+i*2]++;
for(int i=1;i<=maxn;i++)a[i]+=a[i-1];
for(int i=3;i<=maxn;i++)b[i]=b[i-2]+a[i];
for(int i=3;i<=maxn;i++)b[i]+=b[i-1];
for(scanf("%lld",&t);t--;)scanf("%lld%lld",&l,&r),printf("Case #%lld: %lld\n",++f,b[r]-b[l-1]);
return 0;
}