AtCoder agc009_c

(hgs 风格小清新题解)

简单 DP 题。咋这种题都 2400 啊。。。

注意到最终 (A)(B) 都各一定能表示成 (s)(有序)的若干个区间。

于是对这个区间 DP。

我们考虑 (dp_{i,0/1}) 为考虑划分前 (i) 个,第 (i) 个分到 (A/B) 的方案数。

然后转移的话,就 (0) 转移到 (1) (1) 转移到 (0),决策要满足两个限制:

  1. 当前区间内部满足条件;
  2. 区间两端要满足条件。

然后随便推。发现 1 的决策集合是个 ([1,i]) 的后缀,即有下界;2 是个前缀,即有上界。

综合起来就是一个区间?前缀和随便维护一下。

1 可以用分段 for 预处理,2 傻逼写 lower_bound,不傻逼发现单调性,two-pointers 随便维护。

然后做完了?

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int mod=1000000007,inf=0x3f3f3f3f3f3f3f3f;
const int N=100000;
int n,a,b;
int s[N+1];
int Sum[N+1][2];
int dp[N+1][2];
int lft[N+1][2];
int sum(int l,int r,bool tp){
	if(l>r)return 0;
	return (Sum[r][tp]-Sum[l-1][tp])%mod;
}
signed main(){
	cin>>n>>a>>b;
	for(int i=1;i<=n;i++)scanf("%lld",s+i);
	for(int i=1,ie;i<=n;i=ie+1){
		ie=i;while(ie+1<=n&&s[ie+1]-s[ie]>=a)ie++;
		for(int j=i;j<=ie;j++)lft[j][0]=i;
	}
	for(int i=1,ie;i<=n;i=ie+1){
		ie=i;while(ie+1<=n&&s[ie+1]-s[ie]>=b)ie++;
		for(int j=i;j<=ie;j++)lft[j][1]=i;
	}
	dp[0][0]=dp[0][1]=Sum[0][0]=Sum[0][1]=1;
	int las0=0,las1=0;
	s[0]=-inf,s[n+1]=inf;
	for(int i=1;i<=n;i++){
		while(las0+1<i&&s[las0+1]<=s[i+1]-a)las0++;
		while(las1+1<i&&s[las1+1]<=s[i+1]-b)las1++;
		dp[i][0]=sum(lft[i][0]-1,las1,1);
		dp[i][1]=sum(lft[i][1]-1,las0,0);
		Sum[i][0]=(Sum[i-1][0]+dp[i][0])%mod;
		Sum[i][1]=(Sum[i-1][1]+dp[i][1])%mod;
	}
	cout<<(dp[n][0]+dp[n][1]+10*mod)%mod;
	return 0;
}
珍爱生命,远离抄袭!
原文地址:https://www.cnblogs.com/ycx-akioi/p/AtCoder-agc009-c.html