[COCI2010-2011#5] DVONIZ
阿新 • • 發佈:2021-06-26
[COCI2010-2011#5] DVONIZ
題意:
定義長度為 \(2\times K\) 並且前 \(K\) 個元素之和不超過 \(S\) 且後 \(K\) 各元素之和也不超過 \(S\) 的數列為 INTERESTING 串,給定長度為 \(N\) 的數列 \(A\) ,對於每個元素,求出以該元素為起點的最長 INTERESTING 串。(\(2 \le N \le 100000,1\le S \le 2\times10^9\))
首先我們定義 \(\text{mid}\) 為一個 INTERESTING 串的中心:即分界點。設 \(\text{L}\),\(\text{K}\) 分別為這個串的左端點和右端點,而這個串長度為 \(2\times K\)
遞推式為:
\[ans[i]=\max(ans[i-1]-2,ans[i]) (1\le i \le n) \] 那麼問題變成了求對於每個位置作為 \(\text{mid}\)
在取完之後,我們根據左右指標所在的位置 \(L,R\) 來得到此時能取到的最大的 \(K\)。 即:
\[K=\min(R-mid,mid-l+1) \] 而更新答案我們這樣更新:
\[ans[mid-K+1]=2\times K \] 在結束後我們再遍歷一遍,通過上文得到的遞推式推出所有的 \(\text{ans}\)
程式碼如下:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int MAXN = 1e5+5;
int n;
ll s,a[MAXN],len[MAXN];
int main()
{
scanf("%d %lld",&n,&s);
for(int i=1;i<=n;++i)
scanf("%lld",&a[i]);
int l=1,r=0;
ll ls=0,rs=0;
while(rs+a[r+1]<s&&r<n) rs+=a[++r];
for(int i=1;i<=n;++i)
{
ls+=a[i];
rs-=a[i];
while(ls>s&&l<=i)
{
ls-=a[l];
++l;
}
while(rs+a[r+1]<=s&&r<n) rs+=a[++r];
int le=min(i-l+1,r-i);
if(le>0) len[i-le+1]=le*2;
}
for(int i=1;i<n;++i) len[i]=max(len[i-1]-2,len[i]);
for(int i=1;i<n;++i)
printf("%lld\n",len[i]);
printf("0\n");
return 0;
}