2020牛客暑期多校训练营(第八场) Enigmatic Partition

原题
题目描述
在这里插入图片描述
样例
输入

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) 是首尾差等于 2 2 并且相邻两个差最多为 1 1 的递增序列。
若设第一段的数值为 a 1 a1 ,则第二段的数值为 a + 1 a+1 ,第三段的数值为 a + 2 a+2 。我们再设第一段的长度为 b 1 b1 ,第二段的长度为 b 2 b2 ,第三段的长度为 b 3 b3
则我们可以得出以下结论

  • a b 1 + ( a + 1 ) b 2 + ( a + 2 ) b 3 = 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 m + b 2 + 2 b 3 = 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;
}

猜你喜欢

转载自blog.csdn.net/bbbll123/article/details/107886840