牛客多校8 - Enigmatic Partition(二阶差分)

题目链接:点击查看

题目大意:首先定义 “ n 的拆分 ” 是 n = a[ 1 ] + a[ 2 ] + ... + a[ m ] ,在本题中,n 的拆分需要满足几个条件:

  1. a[ i ] <= a[ i + 1 ] <= a[ i ] + 1 , i ∈ [ 1 , m ]
  2.  1 <= a[ i ] <= n , i ∈ [ 1 , m ]
  3. a[ m ] = a[ 1 ] + 2 

设 f( n ) 为满足上述所有条件下,n 的拆分有多少种,现在给出 t 组查询,每组查询给出一对 [ l , r ] ,求 f( l ) + f( l + 1 ) + ... + f( r )

题目分析:官方题解的做法是枚举 l ,因为每个数一定由连续的 l , l + 1 和 l + 2 组成,暴力去维护 f( n ) ,不过我没看懂,这里就不多展开了

还有一种更加优秀的做法,暂且叫他二阶差分吧,注意是二阶差分,不是二维差分

参考博客:https://www.cnblogs.com/rair/p/13430729.html

 

 

 

(最后一个图的num2应该打在13的位置,昨晚上没检查出来,不要被误导(狗头)) 

最后再说一下四个数的特征:

  1. num1:111...123
  2. num2:122...223
  3. num3:num2 + 2
  4. num4: 123...333 + 3

代码:

#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
#include<bitset>
#include<unordered_map>
using namespace std;

typedef long long LL;

typedef unsigned long long ull;

const int inf=0x3f3f3f3f;

const int N=1e5+100;

LL sum[N*10];

void init()
{
	for(int i=1;i<N;i++)//枚举a[1],a[m]=a[1]+2
		for(int m=3;m*i<N;m++)//枚举a[1],a[2]...a[m]的m
		{
			int num1=i*m+3,num2=(i+1)*m+1;
			int num3=num2+1,num4=(i+2)*m-3+3;
			sum[num1]++,sum[num2]--;
			sum[num3]--,sum[num4]++;
		}
	for(int i=2;i<N;i++)//二阶差分(隔项)
		sum[i]+=sum[i-2];
	for(int i=2;i<N;i++)//一阶差分(还原f(n))
		sum[i]+=sum[i-1];
	for(int i=2;i<N;i++)//前缀和
		sum[i]+=sum[i-1];
}

int main()
{
#ifndef ONLINE_JUDGE
//  freopen("data.in.txt","r",stdin);
//  freopen("data.out.txt","w",stdout);
#endif
//  ios::sync_with_stdio(false);
	init();
	int w;
	cin>>w;
	int kase=0;
	while(w--)
	{
		int l,r;
		scanf("%d%d",&l,&r);
		printf("Case #%d: %lld\n",++kase,sum[r]-sum[l-1]);
	}







    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_45458915/article/details/107777572