• 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;
    }
    
    珍爱生命,远离抄袭!
  • 相关阅读:
    SPLAY,LCT学习笔记(五)
    SPLAY,LCT学习笔记(四)
    SPLAY,LCT学习笔记(三)
    NOI 2012 随机数生成器
    SPLAY,LCT学习笔记(二)
    SPLAY,LCT学习笔记(一)
    bzoj 1503 郁闷的出纳员
    bzoj 1112 poi 2008 砖块
    bzoj 1064 noi2008 假面舞会题解
    数论知识点总结(noip范围)
  • 原文地址:https://www.cnblogs.com/ycx-akioi/p/AtCoder-agc009-c.html
Copyright © 2020-2023  润新知