前言
\(CSP-S\) 模拟赛,确实比前几次简单多了。
-
\(T1~100pts\) : 签到题。
-
\(T2~100pts\) :二分直接跑即可。
-
\(T3~40pts\) :
首先他给的这个快读没法用。
赛时
joker
了,打了个 \(n^2~DP\) ,然后优化了 \(50min\) 换了个转移方程还是 \(n^2\) ,复杂度打假了。因为赛时懒得跑线段树,而且知道这玩意常数太大过不去,赛后听有人说 \(ST\) 表才恍然大悟,成
joker
了 。 -
\(T4~0pts\) :光顾着调 \(T3\) 了,没怎么看。
-
比赛链接 。
\(T1\) 最后一课
签到题,没什么好说的,将军饮马问题 。
点击查看代码
#include<bits/stdc++.h>
#define int __int128
#define endl '\n'
#define sort stable_sort
using namespace std;
const int N=2e5+10;
template<typename Tp> inline void read(Tp&x)
{
x=0;register bool z=true;
register char c=getchar();
for(;c<'0'||c>'9';c=getchar()) if(c=='-') z=0;
for(;'0'<=c&&c<='9';c=getchar()) x=(x<<1)+(x<<3)+(c^48);
x=(z?x:~x+1);
}
void wt(int x){if(x>9)wt(x/10);putchar((x%10)+'0');}
void write(int x){if(x<0)putchar('-'),x=~x+1;wt(x);}
int k,x,y,xx,yy;
signed main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
read(k),read(x),read(y),read(xx),read(yy);
if((y<=k&&yy<=k)||(y>=k&&yy>=k))
{
y=k*2-y;
write((xx-x)*(xx-x)+(yy-y)*(yy-y));
return 0;
}
write((xx-x)*(xx-x)+(yy-y)*(yy-y));
}
\(T2\) 日常
二分直接跑即可,记得排序。
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
#define sort stable_sort
using namespace std;
const int N=1e5+10;
template<typename Tp> inline void read(Tp&x)
{
x=0;register bool z=true;
register char c=getchar();
for(;c<'0'||c>'9';c=getchar()) if(c=='-') z=0;
for(;'0'<=c&&c<='9';c=getchar()) x=(x<<1)+(x<<3)+(c^48);
x=(z?x:~x+1);
}
void wt(int x){if(x>9)wt(x/10);putchar((x%10)+'0');}
void write(int x){if(x<0)putchar('-'),x=~x+1;wt(x);}
int n,m,k;
bool v[N];
struct aa
{
int l,r,x,y;
}e[N];
bool cmp(aa a,aa b) {return a.l==b.l?a.r<b.r:a.l<b.l;}
int ask1(int i)
{
int l=1,r=n,mid,ans=0;
while(l<=r)
{
mid=(l+r)>>1;
if(e[mid].l>i) r=mid-1;
if(e[mid].r<i) l=mid+1;
if(e[mid].l<=i&&e[mid].r>=i)
{
ans=mid;
break;
}
}
return ans;
}
int ask2(int i)
{
int l=1,r=n,mid,ans=0;
while(l<=r)
{
mid=(l+r)>>1;
if(e[mid].x>i) r=mid-1;
if(e[mid].y<i) l=mid+1;
if(e[mid].x<=i&&e[mid].y>=i)
{
ans=mid;
break;
}
}
return ans;
}
signed main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
read(n),read(m),read(k);
for(int i=1,l,r,x,y;i<=n;i++)
{
read(l),read(x),read(y),read(r);
e[i]={l,r,x,y};
}
sort(e+1,e+1+n,cmp);
for(int i;k>=1;k--)
{
read(i);
int ans=ask1(i),anss=ask2(i);
if(ans==0) puts("Failed");
else if(v[ans]) puts("Again");
else if(anss) puts("Perfect");
else puts("Normal");
v[ans]=1;
}
}
\(T3\) 渡尘
部分分
-
\(20pts\) :
纯暴力跑,\(O(n^2m)\) 。
-
\(40pts\) :
\(O(n^2)\) 区间 \(DP\) 。
转移方程:
\[f_{l,r}=\max\{f_{l,r},abs(sum_r-sum_{l-1}),f_{l+1,r},f_{l,r-1}\} \]点击查看代码
#include<bits/stdc++.h> #define int long long #define endl '\n' #define sort stable_sort using namespace std; const int N=5010; template<typename Tp> inline void read(Tp&x) { x=0;register bool z=true; register char c=getchar(); for(;c<'0'||c>'9';c=getchar()) if(c=='-') z=0; for(;'0'<=c&&c<='9';c=getchar()) x=(x<<1)+(x<<3)+(c^48); x=(z?x:~x+1); } void wt(int x){if(x>9)wt(x/10);putchar((x%10)+'0');} void write(int x){if(x<0)putchar('-'),x=~x+1;wt(x);} int n,m,a[N],sum[N],f[N][N]; signed main() { #ifndef ONLINE_JUDGE freopen("in.txt","r",stdin); freopen("out.txt","w",stdout); #endif read(n),read(m); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) f[i][j]=-0x3f3f3f3f; for(int i=1;i<=n;i++) read(a[i]), sum[i]=sum[i-1]+a[i], f[i][i]=abs(a[i]); for(int i=1;i<=n;i++) for(int j=i-1;j>=1;j--) f[i][j]=max({ f[i][j], abs(sum[i]-sum[j-1]), abs(sum[i]-sum[j]), abs(sum[i-1]-sum[j-1]), f[i][j+1],f[i-1][j],f[i-1][j+1] }); for(int l,r;m>=1;m--) read(l),read(r), write(f[r][l]),puts(""); }
-
\(70pts\) :
线段树维护区间最大子段和,类似 山海经 这道题。
记录每个区间的最大前缀和,最大后缀和,最大字段和,区间和。
-
最大字段和 \(=\) 左区间最大后缀 \(+\) 右区间最大前缀。
-
最大前缀和 \(=\max\{\) 左区间最大前缀和,左区间和 \(+\) 右区间最大前缀和 \(\}\) 。最大后缀和同理。
复杂度 \(O(m\log(n))\) ,理论可过,但由于线段树的超级常数,只能拿 \(70pts\) 。
代码没打,沾 \(Hangry\) 的了。点击查看代码
#include <bits/stdc++.h> #define int long long #define lson (id << 1) #define rson (id << 1 | 1) using namespace std ; const int N = 2e5 + 100 ; inline int read() { int x = 0 , f = 1 ; char c = getchar() ; while ( c < '0' || c > '9' ) { if ( c == '-' ) f = -f ; c = getchar() ; } while ( c >= '0' && c <= '9' ) { x = x * 10 + c - '0' ; c = getchar() ; } return x * f ; } int n , m ; int a[N] ; class AVST { public: int Max , sum ; int left_min , right_min ; int left_max , right_max ; } t[N << 2] ; inline unsigned int Absolute ( int x ) { return x >= 0 ? x : -x ; } inline int max( int a , int b ) { return a > b ? a : b ; } inline int min( int a , int b ) { return a < b ? a : b ; } inline void push_up( AVST &Main , AVST Lson , AVST Rson ) { Main.sum = Lson.sum + Rson.sum ; Main.left_max = max( Lson.left_max , Lson.sum + Rson.left_max ) ; Main.left_min = min( Lson.left_min , Lson.sum + Rson.left_min ) ; Main.right_max = max( Rson.right_max , Rson.sum + Lson.right_max ) ; Main.right_min = min( Rson.right_min , Rson.sum + Lson.right_min ) ; Main.Max = max( max( Main.sum , max( Lson.Max , Rson.Max ) ) , max( Absolute( Lson.right_max + Rson.left_max ) , Absolute( Lson.right_min + Rson.left_min ) ) ) ; } void build( int id , int l , int r ) { if ( l == r ) { t[id].Max = Absolute( a[l] ) ; t[id].sum = t[id].left_max = t[id].left_min = t[id].right_max = t[id].right_min = a[l] ; return ; } int mid = ( l + r ) >> 1 ; build( lson , l , mid ) ; build( rson , mid + 1 , r ) ; push_up( t[id] , t[lson] , t[rson] ) ; } AVST Query( int id , int l , int r , int x , int y ) { if ( x <= l && r <= y ) { return t[id] ; } int mid = ( l + r ) >> 1 ; if ( x <= mid && mid < y ) { AVST reso = {0 , 0 , 0 , 0 , 0 , 0} , lef , rig ; lef = Query( lson , l , mid , x , y ) ; rig = Query( rson , mid + 1 , r , x , y ) ; push_up( reso , lef , rig ) ; return reso ; } else { if ( x <= mid ) return Query( lson , l , mid , x , y ) ; if ( y >= mid + 1 ) return Query( rson , mid + 1 , r , x , y ) ; AVST bre ; return bre ; } } signed main() { #ifndef ONLINE_JUDGE freopen( "1.in" , "r" , stdin ) ; freopen( "1.out", "w" ,stdout ) ; #endif n = read() ; m = read() ; for ( int i = 1 ; i <= n ; ++ i ) { a[i] = read() ; } build( 1 , 1 , n ) ; int x , y ; for ( int i = 1 ; i <= m ; ++ i ) { x = read() , y = read() ; if ( i == m ) printf( "%lld" , Query( 1 , 1 , n , x , y ).Max ) ; else printf( "%lld\n" , Query( 1 , 1 , n , x , y ).Max ) ; } }
-
-
\(100pts\) :
因为没有修改,用猫树维护,\(O(n\log(n)+m)\) ,但是我不会。
正解
用 \(sum_i\) 表示前缀和。
则区间 \([l\sim r]\) 和的绝对值就是 \(\max(sum_r-sum_{l-1},sum_{l-1}-sum_r)\) 。
那么问题就转化为在区间 \([l-1\sim r]\) 中找一个最大的 \(sum_x\) 和一个最小的 \(sum_y\) ,\(sum_x-sum_y\) 即为所求。
直接用 \(ST\) 表维护即可,复杂度 \(O(n\log(n)+m)\) 。
注意预处理时循环从 \(0\) 开始,因为 \(l-1\) 可能 \(=0\) 。
这个正解甚至比那些歪解简单得多。
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
#define sort stable_sort
using namespace std;
const int N=2e5+10;
template<typename Tp> inline void read(Tp&x)
{
x=0;register bool z=true;
register char c=getchar();
for(;c<'0'||c>'9';c=getchar()) if(c=='-') z=0;
for(;'0'<=c&&c<='9';c=getchar()) x=(x<<1)+(x<<3)+(c^48);
x=(z?x:~x+1);
}
void wt(int x){if(x>9)wt(x/10);putchar((x%10)+'0');}
void write(int x){if(x<0)putchar('-'),x=~x+1;wt(x);}
int n,m,a[N],sum[N],mx[N][30],mi[N][30];
void RMQ()
{
for(int i=0;i<=n;i++)
for(int j=0;j<=log2(n);j++)
mi[i][0]=mx[i][0]=-0x3f3f3f3f;
for(int i=0;i<=n;i++)
mx[i][0]=sum[i],
mi[i][0]=-sum[i];
for(int j=1;j<=log2(n);j++)
for(int i=0;i<=n-(1<<j)+1;i++)
mx[i][j]=max(mx[i][j-1],mx[i+(1<<(j-1))][j-1]),
mi[i][j]=max(mi[i][j-1],mi[i+(1<<(j-1))][j-1]);
}
int ask_mx(int l,int r)
{
int t=log2(r-l+1);
return max(mx[l][t],mx[r-(1<<t)+1][t]);
}
int ask_mi(int l,int r)
{
int t=log2(r-l+1);
return max(mi[l][t],mi[r-(1<<t)+1][t]);
}
signed main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
read(n),read(m);
for(int i=1;i<=n;i++)
read(a[i]),
sum[i]=sum[i-1]+a[i];
RMQ();
for(int l,r;m>=1;m--)
read(l),read(r),
write(ask_mx(l-1,r)+ask_mi(l-1,r)),puts("");
}