[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
0");
    else printf("%d
%d",maxcnt,minarea);
}
View Code

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);
}
View Code

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;
}
View Code

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]);
}
View Code
原文地址:https://www.cnblogs.com/xutianshu/p/10497782.html