AtCoder agc009_c - Division into Two
阿新 • • 發佈:2020-09-09
(hgs 風格小清新題解)
簡單 DP 題。咋這種題都 2400 啊。。。
注意到最終 \(A\) 和 \(B\) 都各一定能表示成 \(s\)(有序)的若干個區間。
於是對這個區間 DP。
我們考慮 \(dp_{i,0/1}\) 為考慮劃分前 \(i\) 個,第 \(i\) 個分到 \(A/B\) 的方案數。
然後轉移的話,就 \(0\) 轉移到 \(1\) \(1\) 轉移到 \(0\),決策要滿足兩個限制:
- 當前區間內部滿足條件;
- 區間兩端要滿足條件。
然後隨便推。發現 1 的決策集合是個 \([1,i]\) 的字尾,即有下界;2 是個字首,即有上界。
綜合起來就是一個區間?字首和隨便維護一下。
1 可以用分段 for
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; }