前言
\(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("");
}