6.28集训--集训模拟赛2

总结


第一题:n只有4,直接暴力
第二题:Tarjan缩点之后跑一个最长路
第三题:DP
第四题:思维量较大

A、翻转游戏

题目描述


分析

\(n\)的范围很小,所以我们考虑状压DP
我们设\(f[i][j][k][m]\)为第一行的状态为\(i\),第二行的状态为\(j\),第三行的状态为\(k\),第四题的状态为\(m\)所需要的最小步数
所以我们暴力枚举6重循环,时间复杂度为\(15 \times 15 \times 15 \times 15 \times 4 \times 4\)

考场95分代码

#include<bits/stdc++.h>
using namespace std;
const int maxn=5;
int f[1<<maxn][1<<maxn][1<<maxn][1<<maxn];
int zt[maxn];
int main(){
    memset(f,0x3f,sizeof(f));
    for(int i=1;i<=4;i++){
        char s[10];
        scanf("%s",s);
        for(int j=0;j<4;j++){
            if(s[j]=='b'){
                zt[i]+=(1<<j);
            }
        }
    }
    f[zt[1]][zt[2]][zt[3]][zt[4]]=0;
    for(int i=0;i<(1<<4);i++){
        for(int j=0;j<(1<<4);j++){
            for(int k=0;k<(1<<4);k++){
                for(int m=0;m<(1<<4);m++){
                    for(int d=1;d<=4;d++){
                        if(d==1){
                            for(int n=1;n<=4;n++){
                                if(n==1){
                                    int now=i^(1<<(n-1));
                                    now=now^(1<<n);
                                    f[now][j^(1<<(n-1))][k][m]=min(f[now][j^(1<<(n-1))][k][m],f[i][j][k][m]+1);
                                } else if(n==2 || n==3){
                                    int now=i^(1<<(n-1));
                                    now=now^(1<<n);
                                    now=now^(1<<(n-2));
                                    f[now][j^(1<<(n-1))][k][m]=min(f[now][j^(1<<(n-1))][k][m],f[i][j][k][m]+1);
                                } else {
                                    int now=i^(1<<(n-1));
                                    now=now^(1<<(n-2));
                                    f[now][j^(1<<(n-1))][k][m]=min(f[now][j^(1<<(n-1))][k][m],f[i][j][k][m]+1);
                                }
                            }
                        } else if(d==2){
                            for(int n=1;n<=4;n++){
                                if(n==1){
                                    int now=j^(1<<(n-1));
                                    now=now^(1<<n);
                                    f[i^(1<<(n-1))][now][k^(1<<(n-1))][m]=min(f[i^(1<<(n-1))][now][k^(1<<(n-1))][m],f[i][j][k][m]+1);
                                } else if(n==2 || n==3){
                                    int now=j^(1<<(n-1));
                                    now=now^(1<<n);
                                    now=now^(1<<(n-2));
                                    f[i^(1<<(n-1))][now][k^(1<<(n-1))][m]=min(f[i^(1<<(n-1))][now][k^(1<<(n-1))][m],f[i][j][k][m]+1);
                                } else {
                                    int now=j^(1<<(n-1));
                                    now=now^(1<<(n-2));
                                    f[i^(1<<(n-1))][now][k^(1<<(n-1))][m]=min(f[i^(1<<(n-1))][now][k^(1<<(n-1))][m],f[i][j][k][m]+1);
                                }
                            }
                        } else if(d==3){
                            for(int n=1;n<=4;n++){
                                if(n==1){
                                    int now=k^(1<<(n-1));
                                    now=now^(1<<n);
                                    f[i][j^(1<<(n-1))][now][m^(1<<(n-1))]=min(f[i][j^(1<<(n-1))][now][m^(1<<(n-1))],f[i][j][k][m]+1);
                                } else if(n==2 || n==3){
                                    int now=k^(1<<(n-1));
                                    now=now^(1<<n);
                                    now=now^(1<<(n-2));
                                    f[i][j^(1<<(n-1))][now][m^(1<<(n-1))]=min(f[i][j^(1<<(n-1))][now][m^(1<<(n-1))],f[i][j][k][m]+1);
                                } else {
                                    int now=k^(1<<(n-1));
                                    now=now^(1<<(n-2));
                                    f[i][j^(1<<(n-1))][now][m^(1<<(n-1))]=min(f[i][j^(1<<(n-1))][now][m^(1<<(n-1))],f[i][j][k][m]+1);
                                }
                            }
                        } else {
                            for(int n=1;n<=4;n++){
                                if(n==1){
                                    int now=m^(1<<(n-1));
                                    now=now^(1<<n);
                                    f[i][j][k^(1<<(n-1))][now]=min(f[i][j][k^(1<<(n-1))][now],f[i][j][k][m]+1);
                                } else if(n==2 || n==3){
                                    int now=m^(1<<(n-1));
                                    now=now^(1<<n);
                                    now=now^(1<<(n-2));
                                    f[i][j][k^(1<<(n-1))][now]=min(f[i][j][k^(1<<(n-1))][now],f[i][j][k][m]+1);
                                } else {
                                    int now=m^(1<<(n-1));
                                    now=now^(1<<(n-2));
                                    f[i][j][k^(1<<(n-1))][now]=min(f[i][j][k^(1<<(n-1))][now],f[i][j][k][m]+1);
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    int ans=min(f[0][0][0][0],f[15][15][15][15]);
    if(ans==0x3f3f3f3f) printf("Impossible\n");
    else printf("%d\n",ans);
    return 0;
}

100分代码

因为我们的状态不是从0开始的,所以我们不能只从状态为0正着开始枚举
比如下面这一组数据

bbbb
bwwb
bwwb
bbbb

正解应该输出4,但是上面的代码却输出6
解决这一个问题,我们倒着枚举一遍就可以了

#include<bits/stdc++.h>
using namespace std;
const int maxn=5;
int f[1<<maxn][1<<maxn][1<<maxn][1<<maxn];
int zt[maxn];
int main(){
    memset(f,0x3f,sizeof(f));
    for(int i=1;i<=4;i++){
        char s[10];
        scanf("%s",s);
        for(int j=0;j<4;j++){
            if(s[j]=='b'){
                zt[i]+=(1<<j);
            }
        }
    }
    f[zt[1]][zt[2]][zt[3]][zt[4]]=0;
    for(int i=0;i<(1<<4);i++){
        for(int j=0;j<(1<<4);j++){
            for(int k=0;k<(1<<4);k++){
                for(int m=0;m<(1<<4);m++){
                    for(int d=1;d<=4;d++){
                        if(d==1){
                            for(int n=1;n<=4;n++){
                                if(n==1){
                                    int now=i^(1<<(n-1));
                                    now=now^(1<<n);
                                    f[now][j^(1<<(n-1))][k][m]=min(f[now][j^(1<<(n-1))][k][m],f[i][j][k][m]+1);
                                } else if(n==2 || n==3){
                                    int now=i^(1<<(n-1));
                                    now=now^(1<<n);
                                    now=now^(1<<(n-2));
                                    f[now][j^(1<<(n-1))][k][m]=min(f[now][j^(1<<(n-1))][k][m],f[i][j][k][m]+1);
                                } else {
                                    int now=i^(1<<(n-1));
                                    now=now^(1<<(n-2));
                                    f[now][j^(1<<(n-1))][k][m]=min(f[now][j^(1<<(n-1))][k][m],f[i][j][k][m]+1);
                                }
                            }
                        } else if(d==2){
                            for(int n=1;n<=4;n++){
                                if(n==1){
                                    int now=j^(1<<(n-1));
                                    now=now^(1<<n);
                                    f[i^(1<<(n-1))][now][k^(1<<(n-1))][m]=min(f[i^(1<<(n-1))][now][k^(1<<(n-1))][m],f[i][j][k][m]+1);
                                } else if(n==2 || n==3){
                                    int now=j^(1<<(n-1));
                                    now=now^(1<<n);
                                    now=now^(1<<(n-2));
                                    f[i^(1<<(n-1))][now][k^(1<<(n-1))][m]=min(f[i^(1<<(n-1))][now][k^(1<<(n-1))][m],f[i][j][k][m]+1);
                                } else {
                                    int now=j^(1<<(n-1));
                                    now=now^(1<<(n-2));
                                    f[i^(1<<(n-1))][now][k^(1<<(n-1))][m]=min(f[i^(1<<(n-1))][now][k^(1<<(n-1))][m],f[i][j][k][m]+1);
                                }
                            }
                        } else if(d==3){
                            for(int n=1;n<=4;n++){
                                if(n==1){
                                    int now=k^(1<<(n-1));
                                    now=now^(1<<n);
                                    f[i][j^(1<<(n-1))][now][m^(1<<(n-1))]=min(f[i][j^(1<<(n-1))][now][m^(1<<(n-1))],f[i][j][k][m]+1);
                                } else if(n==2 || n==3){
                                    int now=k^(1<<(n-1));
                                    now=now^(1<<n);
                                    now=now^(1<<(n-2));
                                    f[i][j^(1<<(n-1))][now][m^(1<<(n-1))]=min(f[i][j^(1<<(n-1))][now][m^(1<<(n-1))],f[i][j][k][m]+1);
                                } else {
                                    int now=k^(1<<(n-1));
                                    now=now^(1<<(n-2));
                                    f[i][j^(1<<(n-1))][now][m^(1<<(n-1))]=min(f[i][j^(1<<(n-1))][now][m^(1<<(n-1))],f[i][j][k][m]+1);
                                }
                            }
                        } else {
                            for(int n=1;n<=4;n++){
                                if(n==1){
                                    int now=m^(1<<(n-1));
                                    now=now^(1<<n);
                                    f[i][j][k^(1<<(n-1))][now]=min(f[i][j][k^(1<<(n-1))][now],f[i][j][k][m]+1);
                                } else if(n==2 || n==3){
                                    int now=m^(1<<(n-1));
                                    now=now^(1<<n);
                                    now=now^(1<<(n-2));
                                    f[i][j][k^(1<<(n-1))][now]=min(f[i][j][k^(1<<(n-1))][now],f[i][j][k][m]+1);
                                } else {
                                    int now=m^(1<<(n-1));
                                    now=now^(1<<(n-2));
                                    f[i][j][k^(1<<(n-1))][now]=min(f[i][j][k^(1<<(n-1))][now],f[i][j][k][m]+1);
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    for(int i=(1<<4)-1;i>=0;i--){
        for(int j=(1<<4)-1;j>=0;j--){
            for(int k=(1<<4)-1;k>=0;k--){
                for(int m=(1<<4)-1;m>=0;m--){
                    for(int d=1;d<=4;d++){
                        if(d==1){
                            for(int n=1;n<=4;n++){
                                if(n==1){
                                    int now=i^(1<<(n-1));
                                    now=now^(1<<n);
                                    f[now][j^(1<<(n-1))][k][m]=min(f[now][j^(1<<(n-1))][k][m],f[i][j][k][m]+1);
                                } else if(n==2 || n==3){
                                    int now=i^(1<<(n-1));
                                    now=now^(1<<n);
                                    now=now^(1<<(n-2));
                                    f[now][j^(1<<(n-1))][k][m]=min(f[now][j^(1<<(n-1))][k][m],f[i][j][k][m]+1);
                                } else {
                                    int now=i^(1<<(n-1));
                                    now=now^(1<<(n-2));
                                    f[now][j^(1<<(n-1))][k][m]=min(f[now][j^(1<<(n-1))][k][m],f[i][j][k][m]+1);
                                }
                            }
                        } else if(d==2){
                            for(int n=1;n<=4;n++){
                                if(n==1){
                                    int now=j^(1<<(n-1));
                                    now=now^(1<<n);
                                    f[i^(1<<(n-1))][now][k^(1<<(n-1))][m]=min(f[i^(1<<(n-1))][now][k^(1<<(n-1))][m],f[i][j][k][m]+1);
                                } else if(n==2 || n==3){
                                    int now=j^(1<<(n-1));
                                    now=now^(1<<n);
                                    now=now^(1<<(n-2));
                                    f[i^(1<<(n-1))][now][k^(1<<(n-1))][m]=min(f[i^(1<<(n-1))][now][k^(1<<(n-1))][m],f[i][j][k][m]+1);
                                } else {
                                    int now=j^(1<<(n-1));
                                    now=now^(1<<(n-2));
                                    f[i^(1<<(n-1))][now][k^(1<<(n-1))][m]=min(f[i^(1<<(n-1))][now][k^(1<<(n-1))][m],f[i][j][k][m]+1);
                                }
                            }
                        } else if(d==3){
                            for(int n=1;n<=4;n++){
                                if(n==1){
                                    int now=k^(1<<(n-1));
                                    now=now^(1<<n);
                                    f[i][j^(1<<(n-1))][now][m^(1<<(n-1))]=min(f[i][j^(1<<(n-1))][now][m^(1<<(n-1))],f[i][j][k][m]+1);
                                } else if(n==2 || n==3){
                                    int now=k^(1<<(n-1));
                                    now=now^(1<<n);
                                    now=now^(1<<(n-2));
                                    f[i][j^(1<<(n-1))][now][m^(1<<(n-1))]=min(f[i][j^(1<<(n-1))][now][m^(1<<(n-1))],f[i][j][k][m]+1);
                                } else {
                                    int now=k^(1<<(n-1));
                                    now=now^(1<<(n-2));
                                    f[i][j^(1<<(n-1))][now][m^(1<<(n-1))]=min(f[i][j^(1<<(n-1))][now][m^(1<<(n-1))],f[i][j][k][m]+1);
                                }
                            }
                        } else {
                            for(int n=1;n<=4;n++){
                                if(n==1){
                                    int now=m^(1<<(n-1));
                                    now=now^(1<<n);
                                    f[i][j][k^(1<<(n-1))][now]=min(f[i][j][k^(1<<(n-1))][now],f[i][j][k][m]+1);
                                } else if(n==2 || n==3){
                                    int now=m^(1<<(n-1));
                                    now=now^(1<<n);
                                    now=now^(1<<(n-2));
                                    f[i][j][k^(1<<(n-1))][now]=min(f[i][j][k^(1<<(n-1))][now],f[i][j][k][m]+1);
                                } else {
                                    int now=m^(1<<(n-1));
                                    now=now^(1<<(n-2));
                                    f[i][j][k^(1<<(n-1))][now]=min(f[i][j][k^(1<<(n-1))][now],f[i][j][k][m]+1);
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    int ans=min(f[0][0][0][0],f[15][15][15][15]);
    if(ans==0x3f3f3f3f) printf("Impossible\n");
    else printf("%d\n",ans);
    return 0;
}

B、抢掠计划

题目描述




分析

显然,处于同一个强连通分量的点可以互相到达
所以我们将每一个强连通分量分别缩点
缩完点后的图就变成了一个有向无环图
这时,我们就可以用SPFA求出最长路

100分代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e6+5;
int head[maxn],tot=1;
struct asd{
    int from,to,next;
    ll val;
}b[maxn],b2[maxn];
void ad(int aa,int bb,ll cc){
    b[tot].from=aa;
    b[tot].to=bb;
    b[tot].next=head[aa];
    b[tot].val=cc;
    head[aa]=tot++;
}
int h2[maxn],t2=1;
void ad2(int aa,int bb){
    b2[t2].from=aa;
    b2[t2].to=bb;
    b2[t2].next=h2[aa];
    h2[aa]=t2++;
}
int dfn[maxn],low[maxn],dfnc,sta[maxn],top;
int js,shuyu[maxn],siz[maxn];
ll a[maxn],ans[maxn];
void tar(int xx){
    dfn[xx]=low[xx]=++dfnc;
    sta[++top]=xx;
    for(int i=h2[xx];i!=-1;i=b2[i].next){
        int u=b2[i].to;
        if(!dfn[u]){
            tar(u);
            low[xx]=min(low[xx],low[u]);
        } else if(!shuyu[u]){
            low[xx]=min(low[xx],dfn[u]);
        }
    }
    if(dfn[xx]==low[xx]){
        js++;
        while(sta[top]!=xx){
            int y=sta[top--];
            shuyu[y]=js;
            siz[js]++;
        }
        top--;
        shuyu[xx]=js;
        siz[js]++;
    }
}
queue<int> q;
int vis[maxn];
ll dis[maxn];
void SPFA(int xx){
    q.push(xx);
    vis[xx]=1;
    while(!q.empty()){
        int now=q.front();
        q.pop();
        vis[now]=0;
        for(int i=head[now];i!=-1;i=b[i].next){
            int u=b[i].to;
            if(dis[u]<dis[now]+b[i].val){
                dis[u]=dis[now]+b[i].val;
                if(vis[u]==0){
                    q.push(u);
                    vis[u]=1;
                }
            }            
        }
    }
}
int main(){
    memset(head,-1,sizeof(head));
    memset(h2,-1,sizeof(h2));
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++){
        int aa,bb;
        scanf("%d%d",&aa,&bb);
        ad2(aa,bb);
    }
    for(int i=1;i<=n;i++){
        scanf("%lld",&a[i]);
    }
    for(int i=1;i<=n;i++){
        if(!dfn[i]) tar(i);
    }
    for(int i=1;i<=n;i++){
        ans[shuyu[i]]+=a[i];
    }
    for(int i=1;i<=n;i++){
        for(int j=h2[i];j!=-1;j=b2[j].next){
            int u=b2[j].to;
            if(shuyu[i]!=shuyu[u]){
                ad(shuyu[i],shuyu[u],ans[shuyu[u]]);
            }
        }
    }
    memset(vis,0,sizeof(vis));
    for(int i=0;i<maxn;i++){
        dis[i]=-0x3f3f3f3f3f3f3f3f;
    }
    int s,p;
    scanf("%d%d",&s,&p);
    dis[shuyu[s]]=ans[shuyu[s]];
    SPFA(shuyu[s]);
    ll mans=0;
    for(int i=1;i<=p;i++){
        int aa;
        scanf("%d",&aa);
        mans=max(mans,dis[shuyu[aa]]);
    }
    printf("%lld\n",mans);
    return 0;
}

C、测绘

题目描述


分析

这一道题非常显然是一道DP题
我们设\(f[i][j]\)为前\(i\)个数中已经选择了\(j\)个数的价值,并且处于\(i\)位置上的数一定选择
那么就有$ f[i][j]= \min (f[i][j],f[k][j-1]+sum[k][i]);\( 其中\)j-1 \leq k < i\( \)sum[i][j]\(为选走\)i,j\(位置上的数,区间\)[i,j]\(中的数产生的误差 这一道题要注意初始化和最后的处理 我们需要将\)f[i][1]\(和\)f[i][i]\(预处理一下 同时,当\)DP$结束后,因为最右边的价值没有计算,所以我们需要把最右边的价值加上

100分代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=105;
int n,vis[maxn],jud;
ll e,a[maxn],sum[maxn][maxn],f[maxn][maxn];
int main(){
    memset(f,0x3f,sizeof(f));
    scanf("%d%lld",&n,&e);
    for(int i=1;i<=n;i++){
        scanf("%lld",&a[i]);
    }
    for(int i=1;i<=n;i++){
        for(int j=i+1;j<=n;j++){
            for(int k=i+1;k<j;k++){
                sum[i][j]+=abs(a[k]*2-a[i]-a[j]);
            }
        }
    }
    for(int i=1;i<=n;i++) f[i][i]=0;
    for(int i=1;i<=n;i++){
        f[i][1]=0;
        for(int j=1;j<i;j++){
            f[i][1]+=2*abs(a[i]-a[j]);
        }
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=i;j++){
            for(int k=j-1;k<i;k++){
                f[i][j]=min(f[i][j],f[k][j-1]+sum[k][i]);
            }
        }
    }
    for(int i=1;i<n;i++){
        for(int j=1;j<=i;j++){
            ll ans=0;
            for(int k=i+1;k<=n;k++){
                ans+=2*abs(a[k]-a[i]);
            }
            f[i][j]+=ans;
        }
    }
    int jl=n;
    ll ans=0;
    for(int i=1;i<=n;i++){
        ll now=0x3f3f3f3f3f3f3f3f;
        for(int j=i;j<=n;j++){
            now=min(now,f[j][i]);
        }
        if(now<=e){
            ans=now;
            jl=i;
            break;
        }
    }
    printf("%d %lld\n",jl,ans);
    return 0;
}

D、奖学金



分析

数据范围高达 10 万,显然至少是\(O(n∗log(n))\) 才能通过。
我们分析性质中位数 \(ai\) 必须满足:\(n2+1≤i≤C−n2\)
\(i=n2+1\) 时,我们必须选上最小分数最低的前 \(n2\) 的猪。
所以我们可以枚举每一个中位数,用一个维护奖金的大根堆,每枚举完一个中位数,如果当前的奖金比堆顶的小,则交换,始终保证堆的有 \(n2\) 个数,同时用一个数组 \(f[i]\) 维护如果选 \(ai\) 为中位数,前 \(n2\) 个数的最小奖金。
同上,倒序维护,求出 \(g[i]\) 表示,如果选 \(ai\) 为中位数,则后 \(n2\) 个数最小奖金。
显然答案为满足 \(f[i]+g[i]+a[i].w<=F\) 的最大的 \(a[i].s\)

代码

#include <bits/stdc++.h>
const int maxn=2e5+5;
int n,c,F;
std::priority_queue <int> q;
struct Node{
    int s,w;//分数,奖金
} a[maxn];
bool cmp(const Node &a, const Node &b){
    return a.s<b.s;
}
int f[maxn],g[maxn],sum;;
void Init(){
    scanf("%d%d%d", &n,&c,&F);
    for(int i=1;i<=c;++i)
        scanf("%d%d", &a[i].s,&a[i].w);
    std::sort(a+1,a+1+c,cmp);//按成绩升序
}
void Solve(){
    for(int i=1;i<=n/2;++i){//成绩最低的n/2进入队列
        sum+=a[i].w;//累加总奖金
        q.push(a[i].w);//队列是维护奖金的大根堆
    }
    //f[i]:表示以i为中位数前n/2人的最小奖金
    for(int i=n/2+1;i<=c;++i){
        f[i]=sum;
        int top=q.top();
        if(top>a[i].w){//如果当前的奖金小于堆顶则交换掉
            q.pop();
            sum-=top;
            sum+=a[i].w;
            q.push(a[i].w);
        }
    }

    sum=0;
    while(!q.empty()) q.pop();
    for(int i=c;i>=c-n/2+1;--i){//成绩最高的n/2进入队列
        sum+=a[i].w;
        q.push(a[i].w);
    }
    //g[i]:表示以i为中位数后n/2人的最低奖金
    for(int i=c-n/2;i>=1;--i){
        g[i]=sum;
        int top=q.top();
        if(top>a[i].w){//交换
            q.pop();
            sum-=top;
            sum+=a[i].w;
            q.push(a[i].w);
        }
    }
    //中位数的取值范围是[n/2+1,c-n/2]
    //因为要求最大中位数,所以倒序
    for(int i=c-n/2;i>=n/2+1;--i)
        if(a[i].w+f[i]+g[i]<=F){
            printf("%d", a[i].s);
            return;
        }
    printf("-1\n");
}
int main(){
    Init();
    Solve();
    return 0;
}
posted @ 2020-06-28 16:01  liuchanglc  阅读(140)  评论(0编辑  收藏  举报