牛客第八场_E-Enigmatic Partition(神仙差分)

文章目录

  • [E-Enigmatic Partition](https://ac.nowcoder.com/acm/contest/5673/E)
    • 题意
    • 收获
    • 代码

E-Enigmatic Partition

题意

f ( n ) f(n) f(n)表示将 n n n 拆分成相邻两个数差值不超过1且第一项等于最后一项-2的方案有几种。问你区间 f ( l ) 到 f ( r ) f(l)到f(r) f(l)f(r)的和。

收获

这个题我们通过枚举构造数组的长度来确定有每个数字有多少种构造方案,然后通过求差分数组去发现规律。
对于思维题找规律的时候不能盲目的去猜测,猜测的时候也要有点理论依据。注意化繁为简。任何复杂的问题都可以拆分成简单的问题。
分享俩哥哥比较好的博客吧
传送门1
传送门2

代码

#include
using namespace std;

#define ll long long
const int mx=200100;
ll d[mx];
ll ans[mx];
int n=100001;
int main(){
/*
真的是神仙差分题呀
通过枚举长度来表示每个数值有多少种构造方案;
对呀每种长度先统计出原数组,再在原数组进行差分操作
找规律,发现刚好对差分数组再进行隔项差分刚好是有规律的 
很妙的一道差分题 
*/ 
	ios::sync_with_stdio(0);
	// 我们枚举长度为 m 的串可以构造成什么数字 
	for(int m=3;m<=n;m++){
		for(int a=m;a<=n;a+=m){
			d[a+3]++;d[a+2*m]++;
			d[a+2+m]--;d[a+m+1]--;
		}
	}
	// 对于构造的差分数组求隔项差分
	// 然后再求前缀和就是答案 
	for(int i=3;i<=n;i++) d[i]+=d[i-2];
	for(int i=1;i<=n;i++){
		d[i]+=d[i-1];
		ans[i]=ans[i-1]+d[i];
	} 
	
	int r,l,t;cin>>t;
	for(int i=1;i<=t;i++){
		cin>>l>>r;
		cout<<"Case #"<<i<<": "<<ans[r]-ans[l-1]<<"\n";
	} 
} 

你可能感兴趣的:(牛客,差分数组,算法)