模拟50—「第零题·第负一题·第负二题」
第零题
这道题考场上做的很曲折,并且最终没有做出来。
一开始几个思路都是假的,但是我没看出来。
到后面已经明确倍增 \(k\) 的思路了,但是还是在用树上主席树+前缀和,导致没有正确性。
正解关键的一步是 先用倍增求出来每个点跳到第一个死的地方是哪里,记为 \(nxt_i\) 。
然后对 \(nxt_i\) 倍增。
从下到上很简单,如果要从上到下的话,还有些问题,因为直接莽走上下可能并不等价。
需要一个操作就是先让他从上到下的路程上剩余的血量消耗光,然后在从上到下倍增到被消耗光的那个点。
这样是上下就是等价的,很显然。
这题不算很难,但是思考时间不够,总是认为自己很难实现的思路是对的,然而确实没有什么正确性。
心态还容易被搞炸,多想,思考越多,实现越简单。
第负一题
首先可以发现可以在每个左端点做一个简单的 \(dp\) 拿到部分分数 \(f_i=max(f_{i-1},f_{i-2}+a[i])\)
考场上一直在想怎么快速求出这个 \(dp\) 的前缀和,然鹅并没有什么效果。
他让求的是所有区间的答案,显然我们无法遍历所有区间,所以总要想个方式一下计算很多区间的答案。
帮助我们达到这个效果的就是 分治
考场上完全没有想到这个思路,甚至现在也不能很理解这是怎么想到的,暂且当作一种统计全区间问题的一个套路。
分治的思想就是定义 \(solve(l,r)\) 代表计算 \([l,r]\) 内所有区间的答案。
显然可以把所有区间分成两类 ,跨过 \(mid\) 的和没跨过 \(mid\) 的。
对于第二种,直接递归下去计算,现在考虑如何在与 \(O(r-l)\) 相关的复杂度内计算出来跨过 \(mid\) 的答案。
正确的操作方式是从 \(mid\) 向左端点和右端点分别做 \(dp\) 。
计算出来 \(f_{0/1,i},g_{0/1,i}\)分别代表 选/不选 mid/mid+1 的情况下 \(i\) 处的最大值。
转移很简单,重点是拼接。
有两种方式拼接
求出来 \(dp\) 值之后,他们的顺序就不重要了。
列出不等式,解出来选择一个 \(f_{i,0}\) 的范围,然后对 \(g\) 操作一下排个序,就可以二分+前缀和完成操作。
这道题虽然看题解很好写出来,但是对于我还是有几个思维峰点不太想的到。
第负二题
题不错,就是数据造垃圾了。
先转化一下题意,不难发现,如果 \(k\) 可行,那么至少要有一个 大小为 \(k\) 的菱形。
然后推一下柿子在转化一下,可以解出来中心的坐标范围。
就是要让一个 \(max\) 和一个 \(min\) 有交。
可以直接 二分答案加 \(rmq\) 实现 \(nlogn\)
然后就是比较 \(nb\) 的部分了。
根据性质可以发现 \(|f_i-f_{i-1}|\leq1\)
所以我们每次不需要二分答案,而是直接\(check \ \ \ ( f_[i-1]-1,f[i-1],f[i-1]+1)\) 是否合法。
现在考虑如何优化掉 \(rmq\)。
发现其实是让一个范围内的区间有交,而我们可以用单调队列来维护这个值。
每个\(i\) 来说,他管辖的区间就是 \([i-f_i+1,i] \ \ \ (j\leq i)\) \([i,i+f_i-1] \ \ \ (j\geq i )\)
由于\(i\) 和 \(f_i\) 的变化范围有限且单调不减,所以可以用单调队列解决。
注意单调队列无法回到之前的状态,所以在确定答案之前不改变单调队列。
而是通过手动增加、减去这些值来实现。
把同类操作写成函数可以大幅减小调试难度,注意判断队列为空的情况。
code
#include <cstdio>
#include <cstring>
#include <assert.h>
#include <algorithm>
#define R register int
#define scanf Ruusupuu = scanf
#define freopen rsp_5u = freopen
#define fre(x) freopen( #x".in" , "r" , stdin ) , freopen( #x".out" , "w" , stdout )
int Ruusupuu ;
FILE * rsp_5u ;
using namespace std ;
typedef unsigned long long u64;
typedef long long L ;
typedef double D ;
const int N = 5e6 + 10 ;
const int P = 998244353 ;
const int Inf = 1e9 + 98 ;
inline int read(){
int w= 0 ; bool fg = 0 ; char ch = getchar() ;
while( ch < '0' || ch > '9' ) fg |= ( ch == '-' ) , ch = getchar() ;
while( ch >= '0' && ch <= '9' ) w = ( w << 1 ) + ( w << 3 ) + ( ch ^ 48 ) , ch = getchar() ;
return fg ? -w : w ;
}
int n , Ll , X , Y , l [N] , r [N] , f [N] , pow [N] , ans ;
int q [5][N] , h [5] , t [5] ;
u64 A , B ;
u64 xorshift128p(u64 &A, u64 &B) {
u64 T = A, S = B;
A = S;
T ^= T << 23;
T ^= T >> 17;
T ^= S ^ (S >> 26);
B = T;
return T + S;
}
void gen(int n, int L, int X, int Y, u64 A, u64 B, int l[], int r[]) {
for (int i = 1; i <= n; i ++) {
l[i] = xorshift128p(A, B) % L + X;
r[i] = xorshift128p(A, B) % L + Y;
if (l[i] > r[i]) swap(l[i], r[i]);
}
}
void sc(){
n = read() , Ll = read() , X = read() , Y = read() , scanf( "%llu%llu" , &A , &B ) , gen( n , Ll , X , Y , A , B , l , r ) ;
// n = read() ; for( R i = 1 ; i <= n ; i ++ ) l [i] = read() , r [i] = read() ;
}
int getval( int ix , int id ){
if( ix == 1 ) return l [id] + id ;
if( ix == 2 ) return r [id] - id ;
if( ix == 3 ) return l [id] - id ;
if( ix == 4 ) return r [id] + id ;
assert( 0 ) ;
}
int askhead( int ix ){
if( h [ix] <= t [ix] ) return getval( ix , q [ix][h [ix]] ) ;
else return ( ix & 1 ) ? -Inf : Inf ;
}
void moveval( int ix , int val ){
if( ix == 1 || ix == 3 ) while( h [ix] <= t [ix] && val >= getval( ix , q [ix][t [ix]] ) ) t [ix] -- ;
if( ix == 2 || ix == 4 ) while( h [ix] <= t [ix] && val <= getval( ix , q [ix][t [ix]] ) ) t [ix] -- ;
}
void moveid( int ix , int id ){
while( h [ix] <= t [ix] && q [ix][h [ix]] < id ) h [ix] ++ ;
}
void debug(){
for( R i = 1 ; i <= 4 ; i ++ , puts( "" ) ){
printf( "DEBUGING%d %d %d\n" , i , h [i] , t [i] ) ;
for( R j = h [i] ; j <= t [i] ; j ++ ) printf( "%d " , q [i][j] ) ;
}
}
void work(){
f [1] = 1 , q [1][h [1] = t [1] = 1] = 1 ;
q [2][h [2] = t [2] = 1] = 1 ;
q [3][h [3] = t [3] = 1] = 1 ;
q [4][h [4] = t [4] = 1] = 1 ;
for( R i = 2 ; i <= n ; i ++ ){
moveval( 1 , getval( 1 , i ) ) , q [1][++ t [1]] = i ;
moveval( 2 , getval( 2 , i ) ) , q [2][++ t [2]] = i ;
moveid( 3 , i ) , moveid( 4 , i ) ;
{
int k = f [i - 1] ;
if( i < k || i + k > n ) goto ZT ;
int max1 = askhead( 1 ) + k - i , min2 = askhead( 2 ) + i - k ;
int max3 = max( askhead( 3 ) , max( getval( 3 , i + f [i - 1] - 1 ) , getval( 3 , i + f [i - 1] ) ) ) + i + k ;
int min4 = min( askhead( 4 ) , min( getval( 4 , i + f [i - 1] - 1 ) , getval( 4 , i + f [i - 1] ) ) ) - k - i ;
if( max( max1 , max3 ) <= min( min2 , min4 ) ){
f [i] = f [i - 1] + 1 ;
moveval( 3 , getval( 3 , i + f [i - 1] - 1 ) ) , q [3][++ t [3]] = i + f [i - 1] - 1 ;
moveval( 3 , getval( 3 , i + f [i - 1] ) ) , q [3][++ t [3]] = i + f [i - 1] ;
moveval( 4 , getval( 4 , i + f [i - 1] - 1 ) ) , q [4][++ t [4]] = i + f [i - 1] - 1 ;
moveval( 4 , getval( 4 , i + f [i - 1] ) ) , q [4][++ t [4]] = i + f [i - 1] ;
continue ;
}
}
ZT: ; {
int k = f [i - 1] - 1 ;
if( i < k || i + k > n ) goto zt ;
int max1 , min2 ;
int max3 = max( askhead( 3 ) , getval( 3 , i + f [i - 1] - 1 ) ) + i + k ;
int min4 = min( askhead( 4 ) , getval( 4 , i + f [i - 1] - 1 ) ) - i - k ;
if( q [1][h [1]] == i - f [i - 1] ){
if( h [1] + 1 <= t [1] ) max1 = getval( 1 , q [1][h [1] + 1] ) + k - i ;
else max1 = -Inf ;
} else max1 = askhead( 1 ) + k - i ;
if( q [2][h [2]] == i - f [i - 1] ){
if( h [2] + 1 <= t [2] ) min2 = getval( 2 , q [2][h [2] + 1] ) - k + i ;
else min2 = Inf ;
} else min2 = askhead( 2 ) - k + i ;
if( max( max1 , max3 ) <= min( min2 , min4 ) ){
f [i] = f [i - 1] ;
moveid( 1 , i - f [i - 1] + 1 ) , moveid( 2 , i - f [i - 1] + 1 ) ;
moveval( 3 , getval( 3 , i + f [i - 1] - 1 ) ) , q [3][++ t [3]] = i + f [i - 1] - 1 ;
moveval( 4 , getval( 4 , i + f [i - 1] - 1 ) ) , q [4][++ t [4]] = i + f [i - 1] - 1 ;
continue ;
}
}
zt: ;{
f [i] = f [i - 1] - 1 ;
moveid( 1 , i - f [i] + 1 ) , moveid( 2 , i - f [i] + 1 ) ;
}
} pow [0] = 1 ; for( R i = 1 ; i <= n ; i ++ ) pow [i] = ( 1ll * pow [i - 1] * 3 ) % P ;
for( R i = 1 ; i <= n ; i ++ ) ans = ( 0ll + ans + ( 1ll * pow [i - 1] * f [i] ) ) % P ;
printf( "%d\n" , ans ) ;
}
signed main(){
// fre( in ) ;
sc() ;
work() ;
return 0 ;
}
总结
这场爆炸了,主要原因就是T1。
思考一定时间在码,太麻烦一般不对(貌似重复过无数遍)
一定还是先把暴力打了,把题看了,思考是最重要的,否则浪费题目。
T2 貌似很nb,因为完全没想到。

浙公网安备 33010602011771号