nflsoi 7.25 题解
C.#16047数列 / AT_abc265_d Iroha and Haiku
题意
给定一个长度为 NNN 的数列 A=(A0,…,AN−1)A=(A_0,\ldots,A_{N-1})A=(A0,…,AN−1)。
请判断是否存在整数四元组 (x,y,z,w)(x, y, z, w)(x,y,z,w),满足以下所有条件:
- 0≤x<y<z<w≤N0 \leq x < y < z < w \leq N0≤x<y<z<w≤N
- Ax+Ax+1+…+Ay−1=PA_x + A_{x+1} + \ldots + A_{y-1} = PAx+Ax+1+…+Ay−1=P
- Ay+Ay+1+…+Az−1=QA_y + A_{y+1} + \ldots + A_{z-1} = QAy+Ay+1+…+Az−1=Q
- Az+Az+1+…+Aw−1=RA_z + A_{z+1} + \ldots + A_{w-1} = RAz+Az+1+…+Aw−1=R
3≤N≤2×1053 \leq N \leq 2 \times 10^53≤N≤2×105,1≤Ai≤1091 \leq A_i \leq 10^91≤Ai≤109,1≤P,Q,R≤10151 \leq P, Q, R \leq 10^{15}1≤P,Q,R≤1015,输入中的所有数值均为整数。
思路
像先用单调指针找到 x,yx,yx,y,然后向后推着做,无奈只有 92pts,原因是可能存在很多对 (x,y)(x,y)(x,y),yyy 的不固定会影响后面找 zzz。遂换更暴力优美的做法。
考虑到前缀和各自不同,因此考虑所有的前缀和 sis_isi 扔进 set 里面,枚举一个存在的前缀和 s0s_0s0,并判断 s0+ps_0+ps0+p,s0+p+qs_0+p+qs0+p+q,s0+p+q+rs_0+p+q+rs0+p+q+r 是否存在即可。
代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
ll n,p,q,r;
ll i,x,sum;
set<ll>S;
int main()
{
S.insert(0);
scanf("%lld%lld%lld%lld",&n,&p,&q,&r);
for(i=1;i<=n;i++)
{
scanf("%lld",&x);
sum+=x;
S.insert(sum);
}
for(auto x:S)
{
if(S.find(x+p)!=S.end()&&S.find(x+p+q)!=S.end()&&S.find(x+p+q+r)!=S.end())
{
puts("Yes");
return 0;
}
}
puts("No");
return 0;
}
E.#1909 种橙子 / 洛谷 P7306 Strah
题意
Mirko 最害怕的是寻找合适的土地来种植草莓。他的土地可以用一个 N×MN \times MN×M 的矩阵来表示。土地中有些田地适合种植草莓,而有些不适合,因为那里杂草丛生。
Mirko 正在寻找一块合适矩形。当土地中有一块矩形区域包含的所有田地均适合种植草莓,则该矩形被称为合适矩形。
Mirko 还对所有田地的潜力值感兴趣。一块田地的潜力值定义为包含该田地的合适矩形的个数。
求 Mirko 所有田地的潜力值之和。
1≤N,M≤20001 \le N,M \le 20001≤N,M≤2000。
思路
考虑枚举 iii 为底,枚举 jjj 列为右端,计算每个 jjj 新增的贡献。
维护每个点可以无障碍向上延伸的长度 upi,jup_{i,j}upi,j。每一行 iii,用单调栈维护单调递增的 upupup、加入新决策点 jjj,形成形似阶梯状从而计算贡献:
不会算重吗?这题就是要算重!因为要计算包含每个格子的矩形的个数总和。
不过使用单调栈的做法似乎接近 O(n3)O(n^3)O(n3),因为题目没有出完全递增的 upupup 来卡我。
代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll N=2003;
ll n,m;
ll up[N][N];
char c[N][N];
ll stk[N],top;
ll sum(ll x)
{
return x*(x+1)/2;
}
int main()
{
scanf("%lld%lld",&n,&m);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
cin>>c[i][j];
if(c[i][j]=='.')up[i][j]=up[i-1][j]+1;
}
}
ll ans=0;
for(int i=1;i<=n;i++)//以i行为底
{
stk[top=1]=0;
for(int j=1;j<=m;j++)//计算j列上贡献
{
while(top>1&&up[i][stk[top]]>=up[i][j])top--;
stk[++top]=j;
for(int k=top;k>=2;k--)
ans+=(sum(j-stk[k-1])-sum(j-stk[k]))*sum(up[i][stk[k]]);
}
}
printf("%lld",ans);
return 0;
}
F.#16866 LIS 升级 / AT_arc159_d LIS 2
题意
有一个数列 XXX,初始时 XXX 为空。
高桥君依次进行了 i=1,2,…,Ni=1,2,\ldots,Ni=1,2,…,N 的如下操作:
- 将 li,li+1,…,ril_i,l_i+1,\ldots,r_ili,li+1,…,ri 按顺序依次添加到 XXX 的末尾。
请你求出操作结束后,XXX 的狭义单调递增子序列的最大长度。
1≤N≤2×1051\leq N\leq 2\times 10^51≤N≤2×105,1≤li≤ri≤1091\leq l_i\leq r_i\leq 10^91≤li≤ri≤109。
思路
很经典的题目。设 fif_ifi 表示,以第 iii 次操作的 rir_iri 为结尾的最长子序列长度。那么:
fi=max{fj+ri−li+1(rj<li),fj+ri−rj(li≤rj<ri)}f_i=\max\{f_j+r_i-l_i+1(r_j<l_i),f_j+r_i-r_j(l_i\le r_j< r_i)\}fi=max{fj+ri−li+1(rj<li),fj+ri−rj(li≤rj<ri)}
区间求最大值考虑用线段树维护,max\maxmax 的左右边,我们分别在 [1,li)[1,l_i)[1,li) 查询最大 fjf_jfj、在 [li,ri)[l_i,r_i)[li,ri) 上查询最大 fj−rjf_j-r_jfj−rj,然后在决策点 rir_iri 维护新的 fif_ifi 和 fi−rif_i-r_ifi−ri。
因为 l,rl,rl,r 的值域很大,所以要离散化。具体细节见代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ls u<<1
#define rs u<<1|1
const ll N=4e5+9,inf=3e14;
struct SegT
{
struct node
{
ll ma;
}T[N<<2];
void pushup(ll u)
{
T[u].ma=max(T[ls].ma,T[rs].ma);
}
void build(ll u,ll l,ll r)
{
T[u].ma=-inf;
if(l==r)return;
ll mid=(l+r)>>1;
build(ls,l,mid);
build(rs,mid+1,r);
}
void modify(ll u,ll l,ll r,ll x,ll k)
{
if(l==r)
{
T[u].ma=k;
return;
}
ll mid=(l+r)>>1;
if(x<=mid)modify(ls,l,mid,x,k);
if(x>mid)modify(rs,mid+1,r,x,k);
pushup(u);
}
ll query(ll u,ll l,ll r,ll ql,ll qr)
{
if(ql>qr||qr<l||r<ql)return -inf;
if(ql<=l&&r<=qr)return T[u].ma;
ll mid=(l+r)>>1,ret=-inf;
if(ql<=mid)ret=max(ret,query(ls,l,mid,ql,qr));
if(qr>mid)ret=max(ret,query(rs,mid+1,r,ql,qr));
return ret;
}
}A,B;
ll n;
ll l[N],r[N],L[N],R[N],len[N];
ll aa[N],nn,nnn;
ll f[N];
int main()
{
scanf("%lld",&n);
for(int i=1;i<=n;i++)
{
scanf("%lld%lld",&l[i],&r[i]);
aa[++nn]=l[i];
aa[++nn]=r[i];
len[i]=r[i]-l[i]+1;
}
sort(aa+1,aa+nn+1);
nnn=unique(aa+1,aa+nn+1)-aa;
A.build(1,1,nnn);
B.build(1,1,nnn);
for(int i=1;i<=n;i++)
{
L[i]=lower_bound(aa+1,aa+nnn+1,l[i])-aa;
R[i]=lower_bound(aa+1,aa+nnn+1,r[i])-aa;
}
for(int i=1;i<=n;i++)
{
f[i]=max(len[i],max(A.query(1,1,nnn,1,L[i]-1)+len[i],B.query(1,1,nnn,L[i]+1,R[i]-1)+r[i]));
A.modify(1,1,nnn,R[i],f[i]);
B.modify(1,1,nnn,R[i],f[i]-r[i]);
}
ll ans=-inf;
for(int i=1;i<=n;i++)
ans=max(ans,f[i]);
printf("%lld",ans);
return 0;
}
G.#4256 序列
H.#3322 Wifi 发射器 / 洛谷 P5969 POI2016 Nadajniki
有缘再补。
更多推荐


所有评论(0)