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 种橙子 / 洛谷 P7301 Strah
题意
Mirko 最害怕的是寻找合适的土地来种植草莓。他的土地可以用一个 N×MN \times MN×M 的矩阵来表示。土地中有些田地适合种植草莓,而有些不适合,因为那里杂草丛生。
Mirko 正在寻找一块合适矩形。当土地中有一块矩形区域包含的所有田地均适合种植草莓,则该矩形被称为合适矩形。
Mirko 还对所有田地的潜力值感兴趣。一块田地的潜力值定义为包含该田地的合适矩形的个数。
求 Mirko 所有田地的潜力值之和。
1≤N,M≤20001 \le N,M \le 20001≤N,M≤2000。
题意
考虑固定枚举每一列 jjj,作为矩形右边所在直线。记 xbi,jxb_{i,j}xbi,j 表示,以 (i,j)(i,j)(i,j) 为右端点,在第 iii 行能向左延伸的最多格子数。
维护一个单调栈,从上到下枚举第 iii 行,每次栈顶加入决策点 xb(i,j)xb(i,j)xb(i,j) 使得栈的元素递增,得到宽为 xbi,jxb{i,j}xbi,j、高为栈的元素个数的矩形。之后计算矩形内组成多少新增的(包含枚举的第 iii 行的)矩形。
栈维护的形状类似这样,红色实线所在行表示在栈种的决策行 iii。
代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll N=2003;
ll n,m;
char c[N][N];
vector<ll>blk[N];
ll xb[N][N];//左边最长延伸
ll stk[N],top;
ll s(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]=='#')blk[j].push_back(i),xb[i][j]=0;else xb[i][j]=xb[i][j-1]+1;}}for(int j=1;j<=m;j++)blk[j].push_back(n+1);ll ans=0;for(int j=1;j<=m;j++){top=0;stk[++top]=0;for(int i=1;i<=n;i++){while(top>1&&xb[stk[top]][j]>=xb[i][j])top--;stk[++top]=i;for(int k=top;k>=2;k--)ans+=s(xb[stk[k]][j])*(s(i-stk[k-1])-s(i-stk[k]));//减去先前的列防止算重,算的是左不大于xb(i,j)的列 //变成阶梯状,左边最长延伸,从下到上递减 //以第i行为底边,计算 i-stk[k] ~ i-stk[k-1] 之间形成的子矩形}}printf("%lld",ans);return 0;
}