[EOJ]2019 ECNU XCPC March Selection #2
rank 14
solved 2
(自闭...其实这次题全都很可做,结果因为E题的严重失误彻底GG了。以后一个题交两三次还没A就一定要想算法的问题了...)
A(dp)
题意:有n个人要从A点到B点,已知每个人到达A点的时间。有一辆无限载客量的车,开始时在A点,已知往返时间为m。怎样安排可以使所有人的等待总时间最短。
(dp数组应该开m+TMAX......考场上因为只开了TMAX一直WA)
upsolved
B(暴力)
题意:坐标系中有n个点(n<=500,max(x,y)<=1000),求一个含最多白点且不含黑点的矩形,求该矩形的最小面积。
一定有白点在矩形的边界上,因此可以O(n^2)枚举上下边界,通过预处理纵向前缀和,可以用O(x)求出包含最多白点且不含黑点的左右边界。实际上离散化后可以复杂度O(n^3)。
O(n^2logn)的做法?
upsolved
#include<bits/stdc++.h> using namespace std; #define rep(i,n) for(int i=1;i<=n;i++) #define pii pair<int,int> #define pb push_back #define st first #define nd second #define mp make_pair typedef long long LL; const int N = 1e3+7; const LL inf =1e18; int n,m; int sum[N][N][2],vis[N],l,R,t,b; int a[N]; int main(){ scanf("%d",&n); l=b=1000; rep(i,n){ int x,y; char c; scanf("%d%d %c",&x,&y,&c); x++; y++; if(c=='H'){ l=min(l,x); R=max(R,x); b=min(b,y); t=max(t,y); sum[x][y][0]++; if(!vis[y]){ a[++m]=y; vis[y]=1; } } else { sum[x][y][1]++; } } sort(a+1,a+1+m); for(int i=l;i<=R;i++) for(int j=b;j<=t;j++){ sum[i][j][0]+=sum[i][j-1][0]; sum[i][j][1]+=sum[i][j-1][1]; } int maxcnt=0,minarea=1e7; rep(i,m) for(int j=i;j<=m;j++){ int cnt=0,s=-1,end=-1; for(int k=l;k<=R;k++){ if(sum[k][a[j]][1]-sum[k][a[i]-1][1]){ if(cnt>maxcnt){ maxcnt=cnt; minarea=(end-s)*(a[j]-a[i]); } else if(cnt==maxcnt&&minarea>(end-s)*(a[j]-a[i])){ minarea=(end-s)*(a[j]-a[i]); } cnt=0; s=-1; end=-1; } else { if(sum[k][a[j]][0]-sum[k][a[i]-1][0]){ if(!cnt){ s=k; } cnt+=sum[k][a[j]][0]-sum[k][a[i]-1][0]; end=k; } } } if(cnt>maxcnt){ maxcnt=cnt; minarea=(end-s)*(a[j]-a[i]); } else if(cnt==maxcnt&&minarea>(end-s)*(a[j]-a[i])){ minarea=(end-s)*(a[j]-a[i]); } } if(maxcnt==0)printf("0\n0"); else printf("%d\n%d",maxcnt,minarea); }
C(树,暴力)
题意:若一棵点权二叉树(n<=1e6)中所有左右儿子互换后的新树和原树完全相同,则称他为一棵对称二叉树。给出一棵树,求最大的对称二叉子树。
暴力判断每一颗子树,首先要满足左右儿子相等,因此大量判断都只需要O(1),而当需要大量递归判断的时候树只能趋*于*衡二叉树,因此可以证明(?)最差也能O(nlogn)完成判断。
#include<bits/stdc++.h> using namespace std; #define rep(i,n) for(int i=1;i<=n;i++) #define pii pair<int,int> #define pb push_back #define st first #define nd second #define mp make_pair typedef long long LL; const int N = 1e6+3; const LL inf =1e18; int l[N],r[N],v[N],L[N],R[N],sz[N],can[N]; int ans,n; void init(int node){ sz[node]=1; if(l[node]!=-1)init(l[node]),sz[node]+=sz[l[node]]; if(r[node]!=-1)init(r[node]),sz[node]+=sz[r[node]]; } void dfs(int node,int bef_node){ if(v[L[node]]!=v[l[bef_node]]||v[R[node]]!=v[r[bef_node]]){ can[node]=0; return ; } can[node]=1; if(L[node]!=-1){ dfs(L[node],l[bef_node]); if(!can[L[node]])can[node]=0; } if(R[node]!=-1){ dfs(R[node],r[bef_node]); if(!can[R[node]])can[node]=0; } if(v[L[node]]!=v[l[bef_node]]||v[R[node]]!=v[r[bef_node]])can[node]=0; } int main(){ scanf("%d",&n); rep(i,n)scanf("%d",&v[i]); rep(i,n)scanf("%d%d",&l[i],&r[i]); rep(i,n)L[i]=r[i],R[i]=l[i]; init(1); rep(i,n){ can[i]=0; if(sz[i]>ans)dfs(i,i); if(can[i]&&sz[i]>ans)ans=sz[i]; } printf("%d",ans); }
D(二分)
题意:有n个人要跳舞(n<=1e4),每个人要跳一定时间,舞池容量为k时,前k个人一起开始跳,有人跳完后第k+1个人加入。给出T,确定最大的k使所有人跳完花费的时间小于等于T。
显然二分k,优先队列判断即可。
(纯签到题,结果开始没发现,去做了自闭的E题...)
2A(1:05)
#include<bits/stdc++.h> using namespace std; #define rep(i,n) for(int i=1;i<=n;i++) #define pii pair<int,int> #define pb push_back #define st first #define nd second #define mp make_pair typedef long long LL; const int N = 1e4+3; const LL inf =1e18; int n,t; int a[N]; int check(int k){ priority_queue<int,vector<int>,greater<int> > q; int now=0,id=k; rep(i,k)q.push(a[i]); while(!q.empty()){ if(q.top()<=now){ q.pop(); } else { now=q.top(); q.pop(); } if(id<n)q.push(a[++id]+now); if(now>t)return 0; } return 1; } int main(){ cin>>n>>t; int l=1,r=n; rep(i,n)cin>>a[i]; int ans=n; while(l<=r){ int mid=(l+r)/2; if(check(mid)){ ans=mid; r=mid-1; } else l=mid+1; } cout<<ans; }
E(bfs)
题意:给出一个n*n的矩阵,每走一步需要时间t,每走三步到(x,y)需要时间a[x][y],求从(1,1)到(n,n)的最短时间。
每个点拆成三个点,最基础的bfs即可。
(也是纯签到题...开始不知道为啥写了dfs,T了最后几个点之后一直以为改改常数就能过,结果一改就是两小时T了十几次,直接导致GG,以后最短路一定得写bfs啊啊啊)
17A...(1:52)
#include<bits/stdc++.h> using namespace std; #define rep(i,n) for(int i=1;i<=n;i++) #define pii pair<int,int> #define pb push_back #define st first #define nd second #define mp make_pair typedef long long LL; const int N = 1e2+3; const LL inf =1e18; const int dx[4]={0,1,0,-1}; const int dy[4]={1,0,-1,0}; int n,t; LL a[N][N],mem[N][N][4]; int valid(int x,int y){ if(x>n||y>n)return 0; if(x<1||y<1)return 0; return 1; } int main(){ cin>>n>>t; rep(i,n) rep(j,n){ cin>>a[i][j]; } rep(i,n) rep(j,n)mem[i][j][0]=mem[i][j][1]=mem[i][j][2]=inf; mem[1][1][0]=0; queue< pair<pii,int> > q; q.push(mp(mp(1,1),0)); while(!q.empty()){ pair<pii,int> h=q.front(); q.pop(); int x=h.st.st; int y=h.st.nd; int step=h.nd; for(int i=0;i<4;i++){ int nx=x+dx[i]; int ny=y+dy[i]; if(valid(nx,ny)&&mem[nx][ny][(step+1)%3]>mem[x][y][step]+t+(step==2? a[nx][ny]:0)){ q.push(mp(mp(nx,ny),(step+1)%3)); mem[nx][ny][(step+1)%3]=mem[x][y][step]+t+(step==2? a[nx][ny]:0); } } } cout<<min(min(mem[n][n][0],mem[n][n][1]),mem[n][n][2]); }