zoukankan      html  css  js  c++  java
  • AGC009C Division into Two

    题意

    (n)个严格升序的数,请你分成两个集合(A)(B),其中一个集合任意两数之差不小于(x),另一集合任意两数之差不小于(y)
    问方案数,集合可以为空。
    $n leq 10^5 $
    传送门

    思路

    又是一道神仙(dp)
    (dp_i)表示当前(B)集合的最后一个数是(a_i)的方案数。
    如果暴力转移就是:$$ dp_i=sum_{j<i and a_i-a_j ge y}dp_j $$
    并且满足区间([j+1,i-1])能够放在(A)集合中
    可以发现,满足条件的(j)是一个区间,因此前缀和优化,最后把答案累加起来就好了。

    代码十分简短

    #include <bits/stdc++.h>
    const int N=100005,mu=1000000007;
    int n,s[N],dp[N],l=0,r=0;
    long long x,y,a[N];
    int main(){
    	scanf("%d%lld%lld",&n,&x,&y);
    	for (int i=1;i<=n;i++) scanf("%lld",&a[i]);
    	if (x>y) std::swap(x,y);
    	for (int i=1;i+2<=n;i++) 
    		if (a[i+2]-a[i]<x){
    			puts("0");return 0;
    		} 
    	dp[0]=s[0]=1;
    	for (int i=1;i<=n;i++){
    		while (a[i]-a[r+1]>=y && r<i-1) r++;
    		if (l<=r){
    			if (l) dp[i]=(s[r]-s[l-1]+mu)%mu;
    			else dp[i]=s[r];	
    		} 
    		if (a[i]-a[i-1]<x) l=i-1;
    		s[i]=(s[i-1]+dp[i])%mu;
    	}
    	int ans=0;
    	for (int i=n;i>=0;i--){
    		ans=(ans+dp[i])%mu;
    		if (a[i+1]-a[i]<x && i<n) break;
    	}
    	printf("%d",ans);
    }
    

    后记

    我好菜啊。以后写(Atcoder space dp)的时候都可以加上思路的第一和最后一句了

    * 生而自由 爱而无畏 *
  • 相关阅读:
    Scala之eq,equals,==的区别
    Spark Streaming流计算特点及代码案例
    刷题50—水壶问题
    刷题49(力扣3道题)
    刷题48——最长回文串
    刷题47——矩形重叠
    刷题46——拼写单词
    刷题45(力扣两道题)
    刷题44——岛屿的最大面积
    刷题43——最长上升子序列
  • 原文地址:https://www.cnblogs.com/flyfeather6/p/11789024.html
Copyright © 2011-2022 走看看