当前位置: 代码迷 >> 综合 >> 【DP】AGC009C Division into Two
  详细解决方案

【DP】AGC009C Division into Two

热度:25   发布时间:2023-09-27 05:54:48.0

分析:

很容易想到DP,设DP[i][0/1]DP[i][0/1]DP[i][0/1]表示已经处理了前i个,末尾一个属于A集合/B集合。

那么DP[i][0]=∑DP[k][1]DP[i][0]=\sum DP[k][1]DP[i][0]=DP[k][1],其中KKK满足以下条件:
1、K&lt;iK&lt;iK<i
2、?j∈[K+2,i],aj?aj?1≥A(B)\forall j\in[K+2,i],a_j-a_{j-1}\geq A(B)?j[K+2,i],aj??aj?1?A(B)
3、ai+1?ak≥B(A)a_{i+1}-a_k\geq B(A)ai+1??ak?B(A)
然后用前缀和优化水过去就行了。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define SF scanf
#define PF printf
#define MAXN 100010
#define MOD 1000000007
using namespace std;
typedef long long ll;
ll a[MAXN],A,B;
int n,lasA1[MAXN],lasB1[MAXN];
ll dp[MAXN][2],sum0[MAXN],sum1[MAXN];
int find(ll val){
    int l=1,r=n,res=0;while(l<=r){
    int mid=(l+r)>>1;if(a[mid]<=val){
    res=mid;l=mid+1;}elser=mid-1;}return res;
}
int main(){
    //freopen("division.in","r",stdin);//freopen("division.out","w",stdout);SF("%d%lld%lld",&n,&A,&B);for(int i=1;i<=n;i++)SF("%lld",&a[i]);for(int i=1;i<=n;i++){
    lasA1[i]=lasA1[i-1];lasB1[i]=lasB1[i-1];if(a[i]-a[i-1]<A||i==1)lasA1[i]=i;if(a[i]-a[i-1]<B||i==1)lasB1[i]=i;}sum0[0]=sum1[0]=1;for(int i=1;i<=n;i++){
    sum0[i]=sum0[i-1];sum1[i]=sum1[i-1];int i1=lasA1[i]-1;int i2=find(a[i+1]-B);if(i==n)i2=n;if(i1<=i2){
    if(i1==0)dp[i][0]=sum1[i2];elsedp[i][0]=(sum1[i2]-sum1[i1-1]+MOD)%MOD;}// PF("<%d %d>\n",i1,i2);i1=lasB1[i]-1;i2=find(a[i+1]-A);if(i==n)i2=n;if(i1<=i2){
    if(i1==0)dp[i][1]=sum0[i2];elsedp[i][1]=(sum0[i2]-sum0[i1-1]+MOD)%MOD;}//PF("[%d %d]\n",i1,i2);/*if(dp[i][0]!=0){PF("{%lld %lld}\n",dp[i][0],dp[i][1]);PF("--------\n");}*/sum0[i]=(sum0[i-1]+dp[i][0])%MOD;sum1[i]=(sum1[i-1]+dp[i][1])%MOD;}PF("%lld",(dp[n][0]+dp[n][1])%MOD);
}