Live2d Test Env

牛客NOIP暑期七天营-提高组1

A思路:排个序建立最短路树即可,可以双指针实现。

考察:贪心,构造。

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int maxn=2000010;
struct in{
    int x,id;
    bool friend operator <(in w,in v){ if(w.x==v.x) return w.id<v.id; return w.x<v.x; }
}s[maxn];
int a[maxn],b[maxn],c[maxn],tot;
int q[maxn],head,tail;
int main()
{
    int N,M;
    scanf("%d%d",&N,&M);
    rep(i,1,N) scanf("%d",&s[i].x),s[i].id=i;
    sort(s+1,s+N+1);
    q[++head]=1;
    rep(i,2,N) {
        while(head>tail&&s[i].x-s[q[tail+1]].x>M) tail++;
        if(head>tail){
            a[i]=s[q[tail+1]].id;
            b[i]=s[i].id;
            c[i]=s[i].x-s[q[tail+1]].x;
        }
        q[++head]=i;
        if(c[i]==0) {
            puts("-1");
            return 0;
        }
    }
    printf("%d\n",N-1);
    rep(i,2,N) printf("%d %d %d\n",a[i],b[i],c[i]);
    return 0;
}

B:显然最大值取决于a[],出现的最高位不同的那一位,假设有最高位的分到A组,不然分到B组,分组后,各取一个x,y,那么ans=min(x^y),这个可以字典树实现。

比较常规。 但是比赛的时候我以为字典树空间不够只能得80分。所以写了分治, 分治复杂度也是O(60*N)的,而且感觉比字典树保险,实现就是每一层,继续分组。

考察:贪心,字典树求最小异或。

#include<bits/stdc++.h>
#define ll long long
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int maxn=2000010;
ll a[maxn],b[maxn],c[maxn],ans=0;
void solve(int p,int L1,int R1,int L2,int R2,ll sum)
{if(p==-1){
        ans=min(ans,sum);
        return ;
    }
    int t1=0,t2=0;
    for(int i=L1;i<=R1;i++){
        if(a[i]&(1LL<<p)) b[++t1]=a[i];
        else c[++t2]=a[i];
    }
    rep(i,1,t1) a[L1+i-1]=b[i];
    rep(i,1,t2) a[L1+t1+i-1]=c[i];
 
    int t3=0,t4=0;
    for(int i=L2;i<=R2;i++){
        if(a[i]&(1LL<<p)) b[++t3]=a[i];
        else c[++t4]=a[i];
    }
    rep(i,1,t3) a[L2+i-1]=b[i];
    rep(i,1,t4) a[L2+t3+i-1]=c[i];
    int F=0;
    if(t1&&t3) F=1,solve(p-1,L1,L1+t1-1,L2,L2+t3-1,sum);
    if(t2&&t4) F=1,solve(p-1,L1+t1,R1,L2+t3,R2,sum);
    if(F) return ;
    solve(p-1,L1,R1,L2,R2,sum+(1LL<<p));
}
int main()
{
    int N; scanf("%d",&N);
    rep(i,1,N) scanf("%lld",&a[i]);
    int p=-1;
    for(int i=60;i>=0;i--){
        int tot=0;
        rep(j,1,N) if(a[j]&(1LL<<i)) tot++;
        if(tot!=0&&tot!=N) {
            p=i; break;
        }
    }
    if(p!=-1){
        int t1=0,t2=0; ans=1LL<<61;
        rep(i,1,N) {
            if(a[i]&(1LL<<p)) b[++t1]=a[i];
            else c[++t2]=a[i];
        }
        rep(i,1,t1) a[i]=b[i];
        rep(i,1,t2) a[t1+i]=c[i];
        solve(p-1,1,t1,t1+1,N,1LL<<p);
    }
    printf("%lld\n",ans);
    return 0;
}

C:求最小字典序下的公共路径长度,由于N比较小,显然就是枚举每个点为根,然后最小字典序的  Σ最短路树LCA到根的距离,预料到码量比较长,就写了个floyd骗分,LCA也直接写的倍增(估计写tarjan会快个10倍),70分水过。   字典序那里先排个序,然后记忆化搜索实线。

考察:最短路,LCA,保证字典序。

#include<bits/stdc++.h>
#define pii pair<int,int>
#define mp make_pair
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int inf=1e9;
const int maxn=2001;
int dis[maxn][maxn];
int Laxt[maxn],Next[6001],To[6001],len[6001],cnt;
int a[6001],b[6001],fa[maxn][12],ans[6001],dep[maxn],N,Q;
bool vis[maxn]; int ind[maxn];
vector<int>G[maxn];
void add(int u,int v,int w)
{
    Next[++cnt]=Laxt[u]; Laxt[u]=cnt; To[cnt]=v; len[cnt]=w;
}
int LCA(int u,int v)
{
    if(dep[u]<dep[v]) swap(u,v);
    for(int i=11;i>=0;i--) {
        if(dep[fa[u][i]]>=dep[v]) u=fa[u][i];
    }
    if(u==v) return u;
    for(int i=11;i>=0;i--) if(fa[u][i]!=fa[v][i]) u=fa[u][i],v=fa[v][i];
    return fa[u][0];
}
set<pii>s;
void dfs(int u,int f)
{
    if(vis[u]) return ;
    vis[u]=1; fa[u][0]=f; dep[u]=dep[f]+1;
    for(int i=0;i<G[u].size();i++) dfs(G[u][i],u);
}
void solve(int p)
{
    rep(i,1,N) vis[i]=0;
    rep(i,1,N) G[i].clear();
    rep(i,1,N)
     for(int j=Laxt[i];j;j=Next[j]){
        if(dis[p][i]+len[j]==dis[p][To[j]]) G[i].push_back(To[j]);
     }
    rep(i,1,N) sort(G[i].begin(),G[i].end());
    dfs(p,0);
    rep(i,1,11) rep(j,1,N) fa[j][i]=fa[fa[j][i-1]][i-1];
    rep(i,1,Q){
         if(!vis[a[i]]||!vis[b[i]]) continue;
         ans[i]=max(ans[i],dis[p][LCA(a[i],b[i])]);
    }
}
int main()
{
    int M,u,v,w;
    scanf("%d%d%d",&N,&M,&Q);
    rep(i,1,Q) ans[i]=-1;
    rep(i,1,N) rep(j,1,N) dis[i][j]=inf;
    rep(i,1,N) dis[i][i]=0;
    rep(i,1,M) {
        scanf("%d%d%d",&u,&v,&w);
        add(u,v,w);
        dis[u][v]=min(dis[u][v],w);
    }
    rep(i,1,Q) scanf("%d%d",&a[i],&b[i]);
    rep(k,1,N)
     rep(i,1,N)
      if(dis[i][k]!=inf)
        rep(j,1,N)
          dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
    rep(i,1,N) solve(i);
    rep(i,1,Q) printf("%d\n",ans[i]);
    return 0;
}

 改为dijstra变为90分了:

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int inf=1e9;
const int maxn=2001;
int dis[maxn][maxn];  bool vis[maxn];
int Laxt[maxn],Next[6001],To[6001],len[6001],cnt;
int a[6001],b[6001],ans[6001],dep[maxn],N,Q;
vector<int>G[maxn],P[maxn];
int son[maxn],sz[maxn],Tp[maxn],fa[maxn];
void add(int u,int v,int w)
{
    Next[++cnt]=Laxt[u]; Laxt[u]=cnt; To[cnt]=v; len[cnt]=w;
}
void dfs1(int u,int f)
{
    sz[u]=1; son[u]=0; dep[u]=dep[f]+1; fa[u]=f;
    for(int i=0;i<P[u].size();i++){
        if(!son[P[u][i]]) {
            int v=P[u][i];
            dfs1(v,u); sz[u]+=sz[v];
            if(sz[v]>sz[son[u]]) son[u]=v;
        }
    }
}
void dfs2(int u,int tp)
{
    Tp[u]=tp;
    if(son[u]) dfs2(son[u],tp);
    for(int i=0;i<P[u].size();i++){
        if(P[u][i]!=son[u])
             dfs2(P[u][i],P[u][i]);
    }
}
int LCA(int u,int v)
{
    while(Tp[u]^Tp[v]) dep[Tp[u]]<dep[Tp[v]]?v=fa[Tp[v]]:u=fa[Tp[u]];
    return dep[u]<dep[v]?u:v;
}
void dfs(int u,int f)
{
    if(vis[u]) return ;
    vis[u]=1; P[f].push_back(u);
    for(int i=0;i<G[u].size();i++) dfs(G[u][i],u);
}
struct ww{
    int dis,u;
    bool friend operator <(ww w,ww v){ return w.dis>v.dis; }
};
priority_queue<ww>q; int inq[maxn];
void SPFA(int S)
{
    rep(i,1,N) dis[S][i]=inf; dis[S][S]=0;
    q.push(ww{0,S});
    while(!q.empty()){
        int u=q.top().u; q.pop(); inq[u]=0;
        for(int i=Laxt[u];i;i=Next[i]) {
            int v=To[i];
            if(dis[S][v]>dis[S][u]+len[i]){
                dis[S][v]=dis[S][u]+len[i];
                if(!inq[v]) inq[v]=1,q.push(ww{dis[S][v],v});
            }
        }
    }
}
void solve(int p)
{
    rep(i,1,N) vis[i]=son[i]=0;
    rep(i,0,N) G[i].clear(),P[i].clear();
    rep(i,1,N)
     for(int j=Laxt[i];j;j=Next[j]){
        if(dis[p][i]+len[j]==dis[p][To[j]]) G[i].push_back(To[j]);
    }
    rep(i,1,N) sort(G[i].begin(),G[i].end());
    dfs(p,0); dfs1(p,0); dfs2(p,p);
    rep(i,1,Q){
         if(!vis[a[i]]||!vis[b[i]]) continue;
         ans[i]=max(ans[i],dis[p][LCA(a[i],b[i])]);
    }
}
int main()
{
    int M,u,v,w;
    scanf("%d%d%d",&N,&M,&Q);
    rep(i,1,Q) ans[i]=-1;
    rep(i,1,N) rep(j,1,N) dis[i][j]=inf;
    rep(i,1,N) dis[i][i]=0;
    rep(i,1,M) {
        scanf("%d%d%d",&u,&v,&w);
        add(u,v,w);
    }
    rep(i,1,Q) scanf("%d%d",&a[i],&b[i]);
    rep(i,1,N) SPFA(i);
    rep(i,1,N) solve(i);
    rep(i,1,Q) printf("%d\n",ans[i]);
    return 0;
}
View Code

按照题解写的,还是90分:

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int inf=1e9;
const int maxn=2001;
int dis[maxn][maxn];  bool vis[maxn];
int Laxt[maxn],Next[6001+maxn],To[6001+maxn],len[6001+maxn],cnt;
int a[6001],b[6001],ans[6001],dep[maxn],N,Q;
vector<int>G[maxn],P[maxn];
int son[maxn],sz[maxn],Tp[maxn],fa[maxn];
void add(int u,int v,int w)
{
    Next[++cnt]=Laxt[u]; Laxt[u]=cnt; To[cnt]=v; len[cnt]=w;
}
void dfs1(int u,int f)
{
    sz[u]=1; son[u]=0; dep[u]=dep[f]+1; fa[u]=f;
    for(int i=0;i<P[u].size();i++){
        if(!son[P[u][i]]) {
            int v=P[u][i];
            dfs1(v,u); sz[u]+=sz[v];
            if(sz[v]>sz[son[u]]) son[u]=v;
        }
    }
}
void dfs2(int u,int tp)
{
    Tp[u]=tp;
    if(son[u]) dfs2(son[u],tp);
    for(int i=0;i<P[u].size();i++){
        if(P[u][i]!=son[u])
             dfs2(P[u][i],P[u][i]);
    }
}
int LCA(int u,int v)
{
    while(Tp[u]^Tp[v]) dep[Tp[u]]<dep[Tp[v]]?v=fa[Tp[v]]:u=fa[Tp[u]];
    return dep[u]<dep[v]?u:v;
}
void dfs(int u,int f)
{
    if(vis[u]) return ;
    vis[u]=1; P[f].push_back(u);
    for(int i=0;i<G[u].size();i++) dfs(G[u][i],u);
}
struct ww{
    int dis,u;
    bool friend operator <(ww w,ww v){ return w.dis>v.dis; }
};
priority_queue<ww>q; int inq[maxn],h[maxn];
void SPFA(int S)
{
    rep(i,0,N) dis[S][i]=inf; dis[S][S]=0;
    q.push(ww{0,S});
    while(!q.empty()){
        int u=q.top().u; q.pop(); inq[u]=0;
        for(int i=Laxt[u];i;i=Next[i]) {
            int v=To[i];
            if(dis[S][v]>dis[S][u]+len[i]){
                dis[S][v]=dis[S][u]+len[i];
                if(!inq[v]) inq[v]=1,q.push(ww{dis[S][v],v});
            }
        }
    }
    if(S==0) {
        rep(i,1,N) h[i]=dis[S][i];
        rep(i,1,N) for(int j=Laxt[i];j;j=Next[j]) len[j]=len[j]+h[i]-h[To[j]];
    }
    else {
        rep(i,1,N) if(dis[S][i]!=inf) dis[S][i]=dis[S][i]+h[i]-h[S];
    }
}
void solve(int p)
{
    rep(i,1,N) vis[i]=son[i]=0;
    rep(i,0,N) G[i].clear(),P[i].clear();
    rep(i,1,N)
     for(int j=Laxt[i];j;j=Next[j]){
        if(dis[p][i]+len[j]-h[i]+h[To[j]]==dis[p][To[j]]) G[i].push_back(To[j]);
    }
    rep(i,1,N) sort(G[i].begin(),G[i].end());
    dfs(p,0); dfs1(p,0); dfs2(p,p);
    rep(i,1,Q){
         if(!vis[a[i]]||!vis[b[i]]) continue;
         ans[i]=max(ans[i],dis[p][LCA(a[i],b[i])]);
    }
}
int main()
{
    int M,u,v,w;
    scanf("%d%d%d",&N,&M,&Q);
    rep(i,1,Q) ans[i]=-1;
    rep(i,1,N) rep(j,1,N) dis[i][j]=inf;
    rep(i,1,N) dis[i][i]=0;
    rep(i,1,N) add(0,i,0);
    rep(i,1,M) {
        scanf("%d%d%d",&u,&v,&w);
        add(u,v,w);
    }
    rep(i,1,Q) scanf("%d%d",&a[i],&b[i]);
    rep(i,0,N) SPFA(i);
    rep(i,1,N) solve(i);
    rep(i,1,Q) printf("%d\n",ans[i]);
    return 0;
}
View Code

 

posted @ 2019-08-19 13:29  nimphy  阅读(289)  评论(0编辑  收藏  举报