前言
- 昨天吉就挂了今天大吉……真准啊。
- 继续连挂。
- T2一个很明显的性质没发现,T3白扔20分。
- 消极消极。
T1
- 模拟题。跪求B哥轻虐
#include<cstdio> #include<iostream> using namespace std; int const N=9; int n,m,tp; int a[N][N]; int stk[N],t,q[N],e; pair<int,int>b[N*N]; long long ans; 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 up(){ for(register int i=1;i<=n;++i){ t=e=0; for(register int j=n;j;--j) if(a[j][i])stk[++t]=a[j][i]; if(!t)continue; q[e=1]=stk[t]; for(register int j=t-1,la=stk[t];j;--j) if(stk[j]==la)q[e]<<=1,ans+=q[e],la=0; else q[++e]=la=stk[j]; for(register int j=1;j<=e;++j){ if(a[j][i]^q[j])tp=1; a[j][i]=q[j]; } for(register int j=e+1;j<=n;++j){ if(a[j][i])tp=1; a[j][i]=0; } } return ; } inline void down(){ for(register int i=1;i<=n;++i){ t=e=0; for(register int j=1;j<=n;++j) if(a[j][i])stk[++t]=a[j][i]; if(!t)continue; q[e=1]=stk[t]; for(register int j=t-1,la=stk[t];j;--j) if(stk[j]==la)q[e]<<=1,ans+=q[e],la=0; else q[++e]=la=stk[j]; for(register int j=1;j<=e;++j){ if(a[n-j+1][i]^q[j])tp=1; a[n-j+1][i]=q[j]; } for(register int j=e+1;j<=n;++j){ if(a[n-j+1][i])tp=1; a[n-j+1][i]=0; } } return ; } inline void left(){ for(register int i=1;i<=n;++i){ t=e=0; for(register int j=n;j;--j) if(a[i][j])stk[++t]=a[i][j]; if(!t)continue; q[e=1]=stk[t]; for(register int j=t-1,la=stk[t];j;--j) if(stk[j]==la)q[e]<<=1,ans+=q[e],la=0; else q[++e]=la=stk[j]; for(register int j=1;j<=e;++j){ if(a[i][j]^q[j])tp=1; a[i][j]=q[j]; } for(register int j=e+1;j<=n;++j){ if(a[i][j])tp=1; a[i][j]=0; } } return ; } inline void right(){ for(register int i=1;i<=n;++i){ t=e=0; for(register int j=1;j<=n;++j) if(a[i][j])stk[++t]=a[i][j]; if(!t)continue; q[e=1]=stk[t]; for(register int j=t-1,la=stk[t];j;--j) if(stk[j]==la)q[e]<<=1,ans+=q[e],la=0; else q[++e]=la=stk[j]; for(register int j=1;j<=e;++j){ if(a[i][n-j+1]^q[j])tp=1; a[i][n-j+1]=q[j]; } for(register int j=e+1;j<=n;++j){ if(a[i][n-j+1])tp=1; a[i][n-j+1]=0; } } return ; } int main(){ //freopen("1.in","r",stdin); //freopen("1.out","w",stdout); n=read(),m=read(); a[read()][read()]=read(),a[read()][read()]=read(); for(register int qwq=1,opt,k,v;qwq<=m;++qwq){ opt=read(),k=read(),v=read(); tp=0; switch(opt){ case 0:up();break; case 1:down();break; case 2:left();break; case 3:right();break; } if(!tp)return printf("%d %lld",qwq-1,ans),0; /*for(register int i=1;i<=n;++i,puts("")) for(register int j=1;j<=n;++j) printf("%d ",a[i][j]); printf("%lld ",ans); if(qwq>=3)return 0;*/ t=0; for(register int i=1;i<=n;++i) for(register int j=1;j<=n;++j) if(!a[i][j])b[++t]=make_pair(i,j); int goal=1+k%t; a[b[goal].first][b[goal].second]=v; } printf("%d %lld",m,ans); return 0; }
T2
- 可以发现最优解的单调区间不超过2,否则必然会有成为累赘的多余区间。
- 直接DP是$Theta(N^2)$的,用线段树在$Theta(NlogN)$的时间复杂度内处理出前后缀max,$Theta(N)$统计答案即可。
#include<cstdio> #include<cstring> #include<algorithm> #define ll long long #define L k<<1 #define R k<<1|1 using namespace std; int const N=11e4; int n,tot; int a[N],c[N]; ll f[N][2],maxx[N<<2]; ll ans,tans; pair<int,int>b[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 ll _max(ll x,ll y){ return x>y?x:y; } ll ask(int l,int r,int x,int y,int k){ //printf("%d %d %d %d %d ",l,r,x,y,k); if(x>y)return 0; if(l>=x&&r<=y)return maxx[k]; int mid=l+r>>1; ll as=0; if(x<=mid)as=ask(l,mid,x,y,L); if(y>mid)as=_max(as,ask(mid+1,r,x,y,R)); return as; } inline void update(int k){ maxx[k]=_max(maxx[L],maxx[R]); return ; } void add(int l,int r,int x,ll y,int k){ //printf("!!%d %d %d %lld %d ",l,r,x,y,k); if(l==r){maxx[k]=y;return ;} int mid=l+r>>1; if(x<=mid)return add(l,mid,x,y,L),update(k); return add(mid+1,r,x,y,R),update(k); } signed main(){ //freopen("1.in","r",stdin); //freopen("1.out","w",stdout); n=read(); for(register int i=1;i<=n;++i)b[i]=make_pair(a[i]=read(),i); sort(b+1,b+n+1); for(register int i=1;i<=n;++i) c[b[i].second]=i; for(register int i=1;i<n;++i) add(1,n,c[i],f[i][0]=ask(1,n,1,c[i]-1,1)+a[i],1); f[n][0]=ask(1,n,1,c[n]-1,1)+a[n],memset(maxx,0,sizeof(maxx)); for(register int i=n;i;--i) add(1,n,c[i],f[i][1]=ask(1,n,1,c[i]-1,1)+a[i],1); for(register int i=1;i<=n;++i)f[i][0]=_max(f[i][0],f[i-1][0]); for(register int i=n;i;--i)f[i][1]=_max(f[i][1],f[i+1][1]); for(register int i=1;i<=n;++i) ans=_max(ans,f[i][0]); for(register int i=1;i<n;++i) tans=_max(tans,f[i][0]+f[i+1][1]); if((ans<<1)>=tans)return printf("%lld.000",ans),0; if(tans&1)return printf("%lld.500",tans>>1),0; return printf("%lld.000",tans>>1),0; }
T3
- 用随机化模拟偏转角度进行排序,跑最大生成树。
- 正确率较高。
#include<cstdio> #include<cmath> #include<cstring> #include<cstdlib> #include<ctime> #include<algorithm> #define ll long long using namespace std; int const N=51,M=203; int n,m; int fa[N]; ll ans; double xx,yy; struct node{ int u,v; ll a,b; }s[M]; 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 ll _max(ll x,ll y){ return x>y?x:y; } int find(int x){ return fa[x]==x?x:fa[x]=find(fa[x]); } inline bool cmp(node x,node y){ return xx*x.a+yy*x.b<xx*y.a+yy*y.b; } int main(){ //freopen("2.in","r",stdin); //freopen("1.out","w",stdout); n=read(),m=read(); for(register int i=1;i<=m;++i) s[i].u=read(),s[i].v=read(),s[i].a=read(),s[i].b=read(); srand(time(NULL)); register int p,q; for(register int h=1;h<=23333;++h){ xx=(rand()%20000-10000)*0.00001,yy=(rand()%20000-10000)*0.00001; sort(s+1,s+m+1,cmp); p=0,q=0; for(register int i=1;i<=n;++i)fa[i]=i; for(register int i=1;i<=m;++i){ int x=find(s[i].u),y=find(s[i].v); if(x==y)continue; fa[x]=y,p+=s[i].a,q+=s[i].b; } ans=_max(ans,1ll*p*p+1ll*q*q); } printf("%.6lf",sqrt(ans)); return 0; }