前言
- 发现现在连搜索都不会打了……T2可以搜索的。
- 期望题一旦卡精度我一般都会爆零啊。
- 还是要自己颓推柿子。
T1
- 先处理出两个前缀和数组$a_i,b_i$。
- 问题转换成了点对$(a_i,b_i,w_i)$的三维偏序问题。
- 然而并不会CDQ,所以将点对按$a_i$排序,然后用线段树或树状数组维护就行了。
- 时间复杂度$Theta(NlogN)$,空间复杂度$Theta(N)$。

#include<cstdio> #include<cstring> #include<algorithm> #define ll long long #define getchar() ((S==T&&(T=(S=buf)+fread(buf,1,L,stdin),S==T))?EOF:*S++) int const N=5e5+5,L=1<<20|1; int n,ans,tot; char buf[L],*S,*T; ll a[N],b[N]; struct Pair{ ll fir; int sec; Pair(){} Pair(ll x,int y):fir(x),sec(y){} }s[N]; struct node{ ll fr; int sc,id; }c[N]; int BIT[N]; inline int read(){ int ss(0),pp(1);char bb(getchar()); for(;bb<48||bb>57;bb=getchar())if(bb=='-')pp=-1; while(bb>=48&&bb<=57)ss=(ss<<1)+(ss<<3)+(bb^48),bb=getchar(); return ss*pp; } inline int _min(int x,int y){ return x<y?x:y; } inline int _max(int x,int y){ return x>y?x:y; } inline int ask(int x){ int as=N; while(x)as=_min(as,BIT[x]),x-=x&-x; return as; } inline void add(int x,int y){ while(x<=tot)BIT[x]=_min(y,BIT[x]),x+=x&-x; return ; } int main(){ //freopen("sequence.in","r",stdin); //freopen("1.out","w",stdout); n=read(); for(register int i=1;i<=n;++i)a[i]=a[i-1]+read(); for(register int i=1;i<=n;++i){ s[i]=Pair(b[i]=b[i-1]+read(),i); if(a[i]>=0&&b[i]>=0)ans=i; } std::sort(s+1,s+n+1,[](Pair skyh,Pair yxs){ return skyh.fir<yxs.fir; }); s[0].fir=s[1].fir-1; for(register int i=1;i<=n;++i) b[s[i].sec]=tot=tot+(s[i].fir!=s[i-1].fir); for(register int i=1;i<=n;++i) c[i].fr=a[i],c[i].sc=b[i],c[i].id=i; std::sort(c+1,c+n+1,[](node skyh,node yxs){ return (skyh.fr^yxs.fr)?skyh.fr<yxs.fr:skyh.sc<yxs.sc; }); memset(BIT,0x3f,tot+1<<2); for(register int i=1;i<=n;++i) ans=_max(ans,c[i].id-ask(c[i].sc)),add(c[i].sc,c[i].id); printf("%d",ans); return 0; }
T2
- 暴力DP其实很好想到的,但考试的时候没有想到枚举根节点。
- 决策单调性可以感性理解一下?然后就可以通过了。
- 时空复杂度$Theta(N^2)$。

#include<cstdio> #define ll long long using namespace std; int const N=5005; ll const lar=1e18; int n; int a[N],s[N][N]; ll w[N],dp[N][N]; inline ll _min(ll x,ll y){ return x<y?x:y; } int main(){ scanf("%d",&n); for(register int i=1;i<=n;++i){ scanf("%lld",&dp[i][i]),w[i]=w[i-1]+dp[i][i]; s[i][i]=i;s[i+1][i]=0; } s[1][0]=1; for(register int i=2;i<=n;++i) for(register int j=1,lt=n-i+1,u;j<=lt;++j){ dp[j][u=j+i-1]=lar; ll wnow=w[u]-w[u-i]; for(register int k=s[j][u-1],lit=s[j+1][u];k<=lit;++k){ ll z=dp[j][k-1]+dp[k+1][u]+wnow; if(dp[j][u]>z)s[j][u]=k,dp[j][u]=z; } } printf("%lld",dp[1][n]); return 0; }
T3
- 将柿子推出来后不难想到暴力。
- 发现每次高斯消元的对象变化很小。
- 于是采用分治消元。

#include<cstdio> #include<cstring> #include<vector> #define ll long long #define getchar() ((S==T&&(T=(S=buf)+fread(buf,1,L,stdin),S==T))?EOF:*S++) using namespace std; int const N=302,M=1e5+5,L=1<<20|1,mod=998244353; int n,m,lt; char buf[L],*S,*T; int head[N],Next[M],du[N],to[M],t; int a[11][N][N]; inline int read(){ int ss(0);char bb(getchar()); while(bb<48||bb>57) bb=getchar(); while(bb>=48&&bb<=57) ss=(ss<<1)+(ss<<3)+(bb^48),bb=getchar(); return ss; } inline void add(int y,int x){ to[++t]=y,++du[x]; Next[t]=head[x],head[x]=t; return ; } inline ll power(ll x,int y=mod-2,ll as=1){ for(;y;y>>=1,x=x*x%mod) if(y&1) as=as*x%mod; return as; } inline int up(int x){ return x<0?x+mod:x; } void MergeGauss(int l,int r,int k){ if(l==r){ if(l^1)printf("%d ",up(a[k-1][1][n])); return ; } int mid=l+r>>1; memcpy(a[k],a[k-1],sizeof(a[k])); for(register int i=mid+1;i<=r;++i){ ll x=power(a[k][i][i]); for(register int j=1;j<=n;++j)a[k][i][j]=x*a[k][i][j]%mod; for(register int j=1;j<n;++j){ if(j==i)continue; ll z=a[k][j][i]; for(register int u=l;u<=r;++u)a[k][j][u]=(-z*a[k][i][u]+a[k][j][u])%mod; a[k][j][n]=(-z*a[k][i][n]+a[k][j][n])%mod; } } MergeGauss(l,mid,k+1); memcpy(a[k],a[k-1],sizeof(a[k])); for(register int i=l;i<=mid;++i){ ll x=power(a[k][i][i]); for(register int j=1;j<=n;++j)a[k][i][j]=x*a[k][i][j]%mod; for(register int j=1;j<n;++j){ if(j==i)continue; ll z=a[k][j][i]; for(register int u=l;u<=r;++u)a[k][j][u]=(-z*a[k][i][u]+a[k][j][u])%mod; a[k][j][n]=(-z*a[k][i][n]+a[k][j][n])%mod; } } MergeGauss(mid+1,r,k+1); return ; } int main(){ n=read()+1,m=read(); for(register int i=1,ff;i<=m;++i) add(read(),read()); for(register int i=1,inow;i<n;++i){ inow=power(du[i]); a[0][i][i]=a[0][i][n]=1; for(register int j=head[i];j;j=Next[j]) a[0][i][to[j]]=up(a[0][i][to[j]]-inow); } return MergeGauss(1,n-1,1),0; }