5.17pkusc模拟赛3

A.走”日”字,判断从(i,j)到(k,l)最少几步走到。(5.17)

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
int r,c,gr,gc,lr,lc;
int dirr[9]={0,1,1,2,2,-1,-1,-2,-2};
int dirc[9]={0,2,-2,1,-1,2,-2,1,-1};
struct node{int rr,cc,dis;};
queue<node>q;
bool vis[105][105];
int bfs(int rr,int cc){
    memset(vis,0,sizeof(vis));
    while(!q.empty()) q.pop();
    q.push((node){rr,cc,0});
    vis[rr][cc]=1;
    while(!q.empty()){
        node now=q.front();q.pop();
        //printf("%d %d\n",now.rr,now.cc);
        for(int i=1;i<=8;i++){
            int nr=now.rr+dirr[i];
            int nc=now.cc+dirc[i];
            if(!vis[nr][nc]&&nr>0&&nc>0&&nr<=r&&nc<=c){
                vis[nr][nc]=1;
                q.push((node){nr,nc,now.dis+1});
                if(nr==lr&&nc==lc) {
                    return now.dis+1;
                }
            }
        }
    }
    return -1;
}
int main(){
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
    while(~scanf("%d%d%d%d%d%d",&r,&c,&gr,&gc,&lr,&lc)){
        if(lr==gr&&lc==gc) {printf("0\n");continue;}
        int t=bfs(gr,gc);
        if(t==-1) printf("impossible\n");
        else printf("%d\n",t);
    }
    return 0;
}

B.1.求无向图割边,2.在多个环里的边数。N<=10000 M<=100000(5.18)
第一问tarjan求割边。
第二问一个bcc的性质:为一下三种中的一种:
1.两点一边 2.简单环 3.多个简单环,一些简单环有公共边。
所以我们求出bcc,判断 点数<边数 即为情况3。

摘自蓝书:

不难发现,每条边恰好属于一个双连通分量,但不同的双连通分量可能会有公共点。可以证明不同双连通分量最多只有一个公共点,且它是割点。任意割点都是至少两个不同双连通分量的公共点。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<vector>
#include<queue>
#include<stack>
#include<cstring>
#define N 10005
#define M 100005
using namespace std;
struct E {int to,nxt;}edge[M*2];
struct EE {int u,v;};
int n,m,tot,idx[N];
int dfn[N],low[N],dfs_clock,bcc_cnt,bccno[N];
int ans1,ans2,points,edges;
stack<EE>s;
void init(){
    tot=2;dfs_clock=0;ans1=0;ans2=0;bcc_cnt=0;
    memset(edge,0,sizeof(edge));
    memset(idx,0,sizeof(idx));
    memset(dfn,0,sizeof(dfn));
    memset(low,0,sizeof(low));
    memset(bccno,0,sizeof(bccno));
}
void addedge(int from,int to){
    edge[tot].to=to;edge[tot].nxt=idx[from];idx[from]=tot++;
}
void dfs(int x,int fa){
    dfn[x]=low[x]=++dfs_clock;
    for(int t=idx[x];t;t=edge[t].nxt){
        E e=edge[t];
        EE ee=(EE){x,e.to};
        if(!dfn[e.to]){
            s.push(ee);
            dfs(e.to,x);
            low[x]=min(low[x],low[e.to]);
            if(low[e.to]>dfn[x]) ans1++;
            if(low[e.to]>=dfn[x]){
                bcc_cnt++;
                edges=0;points=0;
                for(;;){
                    EE xx=s.top();s.pop();edges++;
                    if(bccno[xx.u]!=bcc_cnt){points++;bccno[xx.u]=bcc_cnt;}
                    if(bccno[xx.v]!=bcc_cnt){points++;bccno[xx.v]=bcc_cnt;}
                    if(xx.u==x&&xx.v==e.to) break;
                }
                if(edges>points) ans2+=edges;
            }
        }
        else if(dfn[e.to]<dfn[x] && e.to!=fa){
            s.push(ee);
            low[x]=min(low[x],dfn[e.to]);
        }
    }
}
int main(){
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
    while(scanf("%d%d",&n,&m)&&n+m!=0){
        init();
        for(int i=1;i<=m;i++){
            int x,y;
            scanf("%d%d",&x,&y);x++;y++;
            addedge(x,y);addedge(y,x);
        }
        for(int i=1;i<=n;i++)
            if(!dfn[i]) dfs(i,0);
        printf("%d %d\n",ans1,ans2);
    }
    return 0;
}

C.
D.n*m的矩形有B,R,选取周长最大的矩形,有三种可选矩形:
a.全为B。b.全为R。c.BR相间。(n,m<=1000)(5.17)
考虑全部为B的情况(b的情况可以对map取反,c可以部分取反,共操作4次),up[],left[],right[],记录像上扩展距离
ans=max(2*((r-l+1)+up));//up!=0

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define N 1005
using namespace std;
int map[N][N];
int T,n,m,ans,tot;
int up[N][N],l[N][N],r[N][N];
void doit(){//1洞 
    memset(up,0,sizeof(up));
    memset(l,0,sizeof(l));
    memset(r,0,sizeof(r));
    for(int i=1;i<=m;i++)
        up[1][i]=map[1][i]==0;
    for(int i=2;i<=n;i++)
        for(int j=1;j<=m;j++)
            up[i][j]=map[i][j]==0?up[i-1][j]+1:0;
    /*for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++)
            printf("%d ",up[i][j]);
        printf("\n");
    }*/
    for(int i=1;i<=n;i++){
        l[i][1]=1;
        for(int j=2;j<=m;j++){
            int ll=j;
            l[i][j]=j;
            while(ll>1&&up[i][j]<=up[i][ll-1])
                ll=l[i][ll-1],l[i][j]=ll;
        }
        r[i][m]=m;
        for(int j=m-1;j>=1;j--){
            int rr=j;
            r[i][j]=j;
            while(rr<m&&up[i][j]<=up[i][rr+1])
                rr=r[i][rr+1],r[i][j]=rr;
        }
    }

}
void getans(){
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            if(up[i][j]) ans=max(ans,2*(r[i][j]-l[i][j]+1+up[i][j]));
    /*for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++)
            printf("%d ",2*(r[i][j]-l[i][j]+1+up[i][j]));
        printf("\n");
    }*/
}
int main(){
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
    scanf("%d",&T);
    while(T--){
        tot++;
        ans=0;
        scanf("%d%d\n",&n,&m);
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                char ch;
                scanf("%c",&ch);
                map[i][j]=ch=='B'?1:0;
            }
            scanf("\n");
        }
        doit();getans();
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                map[i][j]=map[i][j]^1;
        doit();getans();
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                if((i+j)&1) map[i][j]=map[i][j]^1;
        doit();getans();
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                map[i][j]=map[i][j]^1;
        doit();getans();
        printf("Case #%d: ",tot);
        printf("%d\n",ans);
    }
    return 0; 
}

E.
F.n只蚂蚁在一条长度为l的线段上爬。每个蚂蚁有一种颜色,总颜色数为k,三个参数x,c,dir,代表坐标,颜色,方向。当两个蚂蚁(c1,c2)相遇,左边的蚂蚁颜色变为(c1+c2)%k,右边的蚂蚁颜色变为c1,在所有蚂蚁都走完时,求各种颜色的在所有时刻的路程。(n<=100000,l<=1000000,k<=40)(5.18)

观察发现,两个蚂蚁相遇,可以等价于左边的蚂蚁继续走不变色,右边的蚂蚁继续走颜色变为(c1+c2)%k,这样我们可以想到n^2暴力。然而注意到颜色只有40种。我们可以从左到右扫描每种颜色对当前位置的答案的贡献。时间复杂度O(nk)

#include<iostream>
#include<cstdio>
#include<algorithm>
#define N 100005
using namespace std;
struct A{int x,c;bool dir;}a[N];
long long s[N][40],ans[N],color_s[N];
int n,k,l,last_r,first_r,f;
int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
bool cmp(A m,A n){return m.x<n.x;}
int main(){
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
    scanf("%d%d%d",&n,&k,&l);
    for(int i=1;i<=n;i++){
        a[i].x=read();a[i].c=read();
        a[i].dir=getchar()=='D';
    }
    sort(a+1,a+1+n,cmp);
    if(a[1].x==0&&a[1].dir==0) a[1].dir=1,a[1].c=0,f=1;
    else if(a[1].x!=0) 
        a[n+1].x=0,a[n+1].c=0,a[n+1].dir=1,n++,sort(a+1,a+1+n,cmp),f=1;
    for(int i=1;i<=n;i++){
        if(!a[i].dir) {
            for(int j=0;j<k;j++) s[i][j]=s[i-1][j];
            color_s[i]=color_s[i-1];
            continue;
        }
        if(!last_r) {first_r=i;color_s[i]=a[i].c;last_r=i;continue;}
        color_s[i]=(color_s[last_r]+a[i].c)%k;
        for(int j=0;j<k;j++)
            s[i][(j+a[i].c)%k]+=s[i-1][j];
        s[i][a[i].c]+=(a[i].x-a[last_r].x); 
        last_r=i;
    }
    /*for(int i=1;i<=n;i++) printf("%d ",color_s[i]);puts("");
    for(int i=1;i<=n;i++){
        for(int j=0;j<k;j++)
            printf("%d ",s[i][j]);
        printf("\n");
    }*/
    last_r=0;
    for(int i=1;i<=n;i++){
        if(a[i].dir) last_r=i,ans[a[i].c]+=2*(l-a[i].x);
        else{
            for(int j=0;j<k;j++) ans[(a[i].c+j)%k]+=s[i][j];
            ans[a[i].c%k]+=(a[i].x-a[last_r].x);
            if(i>=first_r) ans[(color_s[i]+a[i].c)%k]+=(a[i].x+a[first_r].x);
        }
    }
    if(f==1) ans[0]-=2*l;
    for(int i=0;i<k;i++) printf("%.1lf\n",(double)ans[i]*0.5);
    return 0;
}
//0 1 L
发布了87 篇原创文章 · 获赞 7 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/yxr0105/article/details/51441492