福建省队集训 20180711
福建省队集训 20180711
sequence
没有这个单调不降的条件就是个傻逼斜率优化,不过这样的题也不会出现在省选题里...
其实就是把一维的条件升级成二维,cdq分治应该可以做,不过n是1e6
既然没有1e5的部分分这应该就是正解...吧?
然后这里的斜率优化是 >和递减查询,维护上凸壳和单调队列。
没有大样例差差差差评
注意要单独归并然后存起来,因为递归顺序不一样,而且用vector会T
题解复杂度还真是nlog,なんだよ、結構当たんじゃねぇか
#include<bits/stdc++.h>
#define int ll
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#define ll long long
#define FOR(i,a,b) for(register int i=(a);i<=(b);++i)
using namespace std;
inline int read(){
int x=0,pos=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') pos=0;
for(;isdigit(ch);ch=getchar()) x=(x<<1)+(x<<3)+ch-'0';
return pos?x:-x;
}
const int N = 2000201;
int n;
ll a[N],top;
int q[N],id[N];
ll f[N];
int cmp(int aa,int bb){
return a[aa]==a[bb]?aa<bb:a[aa]<a[bb];
}
#define pii pair<int,int>
#define pb push_back
#define fi first
#define se second
#define mp make_pair
int vec[26][N];
inline double Y(int i){
return 1.0*f[i]-1.0*(i*i+i)/2.0;
}
inline double slope(int i,int j){
return (Y(i)-Y(j))/(1.0*(i-j));
}
ll calc(int now,int pre){
return f[pre]-1ll*(now-pre-1)*(now-pre)/2ll+a[now];
}
inline void solve(int dep,int l,int r){
if(l==r) return void();
int mid=(l+r)>>1;
solve(dep+1,l,mid);
top=0;
/* FOR(i,l,mid){
int now=id[i];
while(top>1&&slope(q[top-1],q[top])<slope(q[top],i)) top--;
q[++top]=now;
}*/
int h=1;
FOR(i,l,r){
int now=vec[dep][i];
if(now<=mid){
now=id[now];
while(top>h&&slope(q[top-1],q[top])<slope(q[top],now)) top--;
q[++top]=now;
}else{
now=id[now];
while(h<top&&slope(q[h],q[h+1])>=-now) h++;
if(h<=top) f[now]=max(f[now],calc(now,q[h]));
}
}
solve(dep+1,mid+1,r);
}
void merge(int dep,int l,int r){
if(l==r) return vec[dep][l]=l,void();
int mid=(l+r)>>1;
merge(dep+1,l,mid);merge(dep+1,mid+1,r);int tl=l,tr=mid+1;
FOR(i,l,r) vec[dep][i]=(tl<=mid&&(id[vec[dep+1][tl]]<id[vec[dep+1][tr]]||tr>r))?vec[dep+1][tl++]:vec[dep+1][tr++];
}
int lnk[N];
signed main(){
freopen("sequence.in","r",stdin);
freopen("sequence.out","w",stdout);
n=read();
FOR(i,1,n){
a[i]=read();
id[i]=i;
f[i]=-1e18;
}
sort(id+1,id+n+1,cmp);
merge(1,0,n);
solve(1,0,n);
ll ans=-1e18;
FOR(i,0,n){
ans=max(ans,f[i]-1ll*(n-i)*(n-i+1)/2ll);
}
printf("%lld",ans);
return 0;
}
rope
只想到枚举两种颜色然后全部先染色...
假设绳子上只有两种颜色,那么能折到长度为 2 当且仅当除了头尾以外,每 个极长颜色相同段长度都为偶数。
也就是说,除了第一段以外,每一段的开头的 下标是同奇偶的。
那么对于一种颜色 a,我们先枚举奇偶,再枚举另一种颜色 b。我们首先要 将所有其它颜色染成 a 或 b,代价为 n-x[a]-x[b] (x[i]表示 i 的个数),接着如果某 个位置奇偶性不对并且恰好是 a 和 b 相邻,那么需要额外 1 点代价。
那么我们可以不用枚举 b,只要枚举 a 的每一段,将某个颜色的代价+1,最 后查询最小值,再还原即可。
时间复杂度 O(n)