ABC 略
D
f[i]表示以i结尾的所有子数组的最长递减子序列长度之和,考虑转移,a[i-1]和a[i-2]一定至少有一个比a[i]大
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
const int N=1e6+10;
int T,n,a[N],f[N],ans;
void init()
{
ans=0;
}
void solve()
{
cin>>n;
init();
for(int i=1;i<=n;i++)
cin>>a[i];
for(int i=1;i<=n;i++)
{
int t=0;
if(a[i-1]>a[i]) t=max(t,i-1);
else t=max(t,i-2);
f[i]=f[t]+i;
ans+=f[i];
}
cout<<ans<<endl;
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);cout.tie();
cin>>T;
while(T--) solve();
}
E1
中位数的题一个常见做法是二分中位数,把>=这个数的位置赋为1,否则赋为-1,如果一个区间的和>=0那么中位数成立。下面我们检验是否有区间长度大于k满足区间和>=0,等同于找pre[i]-pre[j]的最大值是否>=0(i-j>=k),我们枚举右端点,左端点我们再找一个前i-k的pre的最小值即可。
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
const int N=3e5+10;
int T,n,k,a[N],ans,ll,rr;
void init()
{
}
bool check(int x)
{
int b[N],pre[N],premin[N],preidx[N];
for(int i=1;i<=n;i++)
if(a[i]>=x) b[i]=1;
else b[i]=-1;
pre[0]=premin[0]=preidx[0]=0;
for(int i=1;i<=n;i++)
{
pre[i]=pre[i-1]+b[i];
if(pre[i]<premin[i-1])
{
premin[i]=pre[i];
preidx[i]=i;
}
else
{
premin[i]=premin[i-1];
preidx[i]=preidx[i-1];
}
}
for(int i=k;i<=n;i++)
{
if(pre[i]-premin[i-k]>=0)
{
ll=preidx[i-k]+1,rr=i;
return true;
}
}
return false;
}
void solve()
{
cin>>n>>k;
init();
for(int i=1;i<=n;i++)
cin>>a[i];
int l=1,r=n;
while(l<=r)
{
int mid=(l+r)/2;
if(check(mid)) {ans=mid;l=mid+1;}
else r=mid-1;
}
cout<<ans<<" "<<ll<<" "<<rr<<endl;
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);cout.tie();
cin>>T;
while(T--) solve();
}