zoukankan      html  css  js  c++  java
  • Codeforces 342

    342 D

    题意

    给你一个 (3×n) 的表格,要求放满 (1×2) 的多米诺骨牌,有些位置.可以放骨牌,有些位置X不能放骨牌。有一个位置O旁边至少有一个多米诺骨牌能够移动到这里(骨牌的宽对着这个格子),问有多少种方法。膜 (10^9+7)
    ((3le nle 10^4))

    Examples

    Input

    5
    ....X
    .O...
    ...X.
    

    Output

    1
    

    Input

    5
    .....
    .O...
    .....
    

    Output

    2
    

    Input

    3
    ...
    ...
    ..O
    

    Output

    4
    

    状压dp。
    对于每一列压一个状态(总共8种情况)。
    关键在于怎么处理O
    方法是,暴力枚举O旁边哪些骨牌能够移到它,总共16-1=15种情况。
    然后想到这15种情况中有交集,然后容斥。
    具体:设 (f(...)) 表示哪几个方向上的骨牌能够移到它,则答案为 (f(1)+f(2)+f(3)+f(4)-f(1,2)-f(1,3)-f(1,4)-f(2,3)-f(2,4)-f(3,4)+f(1,2,3)+f(1,2,4)+f(1,3,4)+f(2,3,4)-f(1,2,3,4))

    Code

    #include<bits/stdc++.h>
    #define maxn 10003
    #define INF 1050000000
    #define mod 1000000007
    using namespace std;//dp[i][j]:在第i列mask中的行被覆盖,并且前i−1列被完全覆盖的放置种数
    int dp[maxn][8],n,no[maxn],X,Y,dx[4]={1,0,-1,0},dy[4]={0,1,0,-1};
    char s[3][maxn],t[3][maxn];
    void PE(int& x,int y){if((x+=y)>=mod)x%=mod;}
    void ME(int& x,int y){if((x+=mod-y)>=mod)x%=mod;}
    int Count(int x){int ret=0;while(x){if(x&1)ret++;x>>=1;}return ret;}
    int solve(){
        for(int i=1;i<=n;i++){
            no[i]=0;
            for(int j=0;j<3;j++){
                if(t[j][i]=='X'){
                    no[i]|=(1<<j);
                }
            }
        }
        for(int i=0;i<=n;i++)for(int j=0;j<8;j++)dp[i][j]=0;
        dp[0][7]=1;
        for(int i=1;i<=n;i++){
            for(int j=0;j<8;j++){
                if(j&no[i])continue;
                dp[i][j|no[i]]=dp[i-1][7-j];
                if(j==3||j==6){
                    PE(dp[i][j|no[i]],dp[i-1][7]);
                }
                if(j==7){
                    PE(dp[i][j|no[i]],dp[i-1][3]);
                    PE(dp[i][j|no[i]],dp[i-1][6]);
                }
            }
        }
        return dp[n][7];
    }
    int main(){
        scanf("%d",&n);
        for(int i=0;i<3;i++){
            scanf("%s",s[i]+1);
            for(int j=1;j<=n;j++){
                if(s[i][j]=='O')X=i,Y=j;
            }
        }
        int ans=0;
        for(int i=1;i<16;i++){
            for(int j=0;j<3;j++)for(int k=1;k<=n;k++)t[j][k]=s[j][k];
            t[X][Y]='X';
            bool ok=1;
            for(int j=0;j<4;j++){
                if(i&(1<<j)){
                    int xx=X+dx[j],xxx=xx+dx[j],yy=Y+dy[j],yyy=yy+dy[j];
                    if(xxx<0||xxx>2||yyy<1||yyy>n||s[xx][yy]=='X'||s[xxx][yyy]=='X'){ok=0;break;}
                    t[xx][yy]=t[xxx][yyy]='X';
                }
            }
            if(!ok)continue;
            int tmp=solve();
            if(Count(i)&1)PE(ans,tmp);
            else ME(ans,tmp);
        }
        printf("%d
    ",ans);
        return 0;
    }
    
    

    342 E

    题意

    一棵树,初始时 (1) 号节点为红色,其他节点为蓝色,有 (m) 次操作:

    1. 把一个蓝色节点涂成红色;
    2. 询问一个节点到最近的红色节点的距离。

    ((2le nle 10^5))

    Examples

    Input
    5 4
    1 2
    2 3
    2 4
    4 5
    2 1
    2 5
    1 2
    2 5
    Output
    0
    3
    2

    解 1

    当红色点个数 (le sqrt{n}) 时暴力查询, (>) 时使用一个玄学的bfs修改。
    (O(nsqrt{n}log n),2121ms)

    Code 1

    #include<bits/stdc++.h>
    #define maxn 100003
    #define INF 1050000000
    using namespace std;
    struct edge{
        int to,next;
    }e[maxn<<1];
    int head[maxn],cnte;
    void add(int u,int v){
        e[++cnte].to=v;
        e[cnte].next=head[u];
        head[u]=cnte;
    }
    int n,lg[maxn],dep[maxn],fa[maxn][23],dis[maxn],a[maxn],cnt,q[maxn],*qhead,*qtail;
    void init(int u,int last){
        fa[u][0]=last;
        for(int i=1;(1<<i)<=dep[u];i++){
            fa[u][i]=fa[fa[u][i-1]][i-1];
        }
        for(int i=head[u];i;i=e[i].next){
            int v=e[i].to;
            if(v==last)continue;
            dep[v]=dep[u]+1;
            init(v,u);
        }
    }
    int lca(int x,int y){
        if(dep[x]<dep[y])swap(x,y);
        while(dep[x]>dep[y]){
            x=fa[x][lg[dep[x]-dep[y]]];
        }
        if(x==y)return x;
        for(int i=lg[dep[x]];i>=0;i--){
            if(fa[x][i]!=fa[y][i]){
                x=fa[x][i];
                y=fa[y][i];
            }
        }
        return fa[x][0];
    }
    void bfs(){
        qhead=qtail=q;
        for(int i=1;i<=cnt;i++)*qtail++=a[i],dis[a[i]]=0;
        while(qhead!=qtail){
            int u=*qhead++;
            for(int i=head[u];i;i=e[i].next){
                int v=e[i].to;
                if(dis[u]+1<dis[v]){
                    dis[v]=dis[u]+1;
                    *qtail++=v;
                }
            }
        }
    }
    int main(){
        int Q;
        scanf("%d%d",&n,&Q);
        for(int i=1;i<n;i++){
            int u,v;
            scanf("%d%d",&u,&v);
            add(u,v);
            add(v,u);
        }
        for(int i=2;i<maxn;i++)lg[i]=lg[i-1]+((1<<(lg[i-1]+1))==i);
        init(1,0);
        for(int i=1;i<=n;i++)dis[i]=INF;
        a[++cnt]=1;
        while(Q--){
            int mo,x;
            scanf("%d%d",&mo,&x);
            if(mo==1){
                a[++cnt]=x;
                if(cnt*cnt>n){
                    bfs();
                    cnt=0;
                }
            }
            else{
                int ans=dis[x];
                for(int i=1;i<=cnt;i++){
                    ans=min(ans,dep[x]+dep[a[i]]-(dep[lca(x,a[i])]<<1));
                }
                printf("%d
    ",ans);
            }
        }
        return 0;
    }
    

    解 2

    (log) 的lca查询改为在欧拉序上用ST表 (O(1)) 查询。
    (O(nsqrt{n}),312ms)

    Code 2

    #include<bits/stdc++.h>
    #define maxn 100003
    #define INF 1050000000
    using namespace std;
    struct edge{
        int to,next;
    }e[maxn<<1];
    int head[maxn],cnte;
    void add(int u,int v){
        e[++cnte].to=v;
        e[cnte].next=head[u];
        head[u]=cnte;
    }
    int n,dep[maxn],lg[maxn<<1],st[maxn<<1][23],dfn[maxn],cntdfn,dis[maxn],a[maxn],cnt,q[maxn],*qhead,*qtail;
    void init(int u,int last){
        st[++cntdfn][0]=u;
        dfn[u]=cntdfn;
        for(int i=head[u];i;i=e[i].next){
            int v=e[i].to;
            if(v==last)continue;
            dep[v]=dep[u]+1;
            init(v,u);
            st[++cntdfn][0]=u;
        }
    }
    int work(int x,int y){return dep[x]<dep[y]?x:y;}
    void initst(){
        for(int len=1;(1<<len)<=cntdfn;len++){
            for(int i=1;i+(1<<len)-1<=cntdfn;i++){
                st[i][len]=work(st[i][len-1],st[i+(1<<(len-1))][len-1]);
            }
        }
    }
    int lca(int x,int y){
        if(dfn[x]>dfn[y])swap(x,y);
        int tmp=lg[dfn[y]-dfn[x]+1];
        return work(st[dfn[x]][tmp],st[dfn[y]-(1<<tmp)+1][tmp]);
    }
    void bfs(){
        qhead=qtail=q;
        for(int i=1;i<=cnt;i++)*qtail++=a[i],dis[a[i]]=0;
        while(qhead!=qtail){
            int u=*qhead++;
            for(int i=head[u];i;i=e[i].next){
                int v=e[i].to;
                if(dis[u]+1<dis[v]){
                    dis[v]=dis[u]+1;
                    *qtail++=v;
                }
            }
        }
    }
    int main(){
        int Q;
        scanf("%d%d",&n,&Q);
        for(int i=1;i<n;i++){
            int u,v;
            scanf("%d%d",&u,&v);
            add(u,v);
            add(v,u);
        }
        for(int i=1;i<=n;i++)dis[i]=INF;
        init(1,0);
        for(int i=2;i<(maxn<<1);i++)lg[i]=lg[i-1]+((1<<(lg[i-1]+1))==i);
        initst();
        a[++cnt]=1;
        while(Q--){
            int mo,x;
            scanf("%d%d",&mo,&x);
            if(mo==1){
                a[++cnt]=x;
                if(cnt*cnt>n){
                    bfs();
                    cnt=0;
                }
            }
            else{
                int ans=dis[x];
                for(int i=1;i<=cnt;i++){
                    ans=min(ans,dep[x]+dep[a[i]]-(dep[lca(x,a[i])]<<1));
                }
                printf("%d
    ",ans);
            }
        }
        return 0;
    }
    

    解 3

    https://blog.csdn.net/acmmmm/article/details/17270855
    树链剖分,开的线段树上每个节点维护两个值:最近红色节点到链顶端的距离 (U) ;最近红色节点到链底端的距离 (D)
    询问时每次跳到一个节点,就在线段树里询问链顶端到当前节点的 (D) 值和链底端到当前节点的 (U) 值。

    Code 3

    #include<bits/stdc++.h>
    #define maxn 100003
    #define INF 1050000000
    using namespace std;
    struct edge{
    	int from,to,next;
    }e[maxn<<1];
    int head[maxn],cnte;
    void add(int u,int v){
    	e[++cnte].to=v;
    	e[cnte].from=u;
    	e[cnte].next=head[u];
    	head[u]=cnte;
    }
    int n,fa[maxn],son[maxn],dep[maxn],sz[maxn],dfn[maxn],num[maxn],rig[maxn],cntdfn,
    top[maxn],cntli[maxn],numli[maxn],dis[maxn];
    
    namespace SEG{
    	struct node{
    		int disup,disdown;
    		node():disup(INF),disdown(INF){}
    	}t[maxn<<2];
    	void pushup(node& t1,const node& t2,const node& t3){
    		t1.disup=min(t2.disup,t3.disup);
    		t1.disdown=min(t2.disdown,t3.disdown);
    	}
    	void change(int p,int l,int r,int pos,int u){
    		if(l==r){
    			t[p].disup=dis[u]+numli[u];
    			t[p].disdown=dis[u]+cntli[top[u]]-numli[u]-1;
    			return;
    		}
    		int mid=(l+r)>>1;
    		if(pos<=mid)change(p<<1,l,mid,pos,u);
    		else change(p<<1|1,mid+1,r,pos,u);
    		pushup(t[p],t[p<<1],t[p<<1|1]);
    	}
    	int query(int p,int l,int r,int seg_l,int seg_r,bool up){
    		if(seg_l<=l&&r<=seg_r){
    			return up?t[p].disup:t[p].disdown;
    		}
    		int mid=(l+r)>>1,ret=INF;
    		if(seg_l<=mid)ret=min(ret,query(p<<1,l,mid,seg_l,seg_r,up));
    		if(seg_r>mid)ret=min(ret,query(p<<1|1,mid+1,r,seg_l,seg_r,up));
    		return ret;
    	}
    }
    
    void initdep(int u,int last){
    	fa[u]=last;
    	sz[u]=1;
    	int mxsz=0;
    	for(int i=head[u];i;i=e[i].next){
    		int v=e[i].to;
    		if(v==fa[u])continue;
    		dep[v]=dep[u]+1;
    		initdep(v,u);
    		sz[u]+=sz[v];
    		if(sz[v]>mxsz)mxsz=sz[v],son[u]=v;
    	}
    }
    void initdfn(int u,int tp){
    	dfn[u]=++cntdfn;
    	num[cntdfn]=u;
    	top[u]=tp;
    	numli[u]=cntli[tp];
    	cntli[tp]++;
    	if(son[u]){
    		initdfn(son[u],tp);
    		for(int i=head[u];i;i=e[i].next){
    			int v=e[i].to;
    			if(v==fa[u]||v==son[u])continue;
    			initdfn(v,v);
    		}
    	}
    	rig[u]=cntdfn;
    }
    void change(int u){
    	for(int v=u;v;v=fa[top[v]]){
    		if(dep[u]-dep[v]<dis[v]){
    			dis[v]=dep[u]-dep[v];
    			SEG::change(1,1,n,dfn[v],v);
    		}
    		else break;
    	}
    }
    int query(int u){
    	int ret=INF;
    	for(int v=u;v;v=fa[top[v]]){
    		ret=min(ret,min(SEG::query(1,1,n,dfn[top[v]],dfn[top[v]]+numli[v],0)-(cntli[top[v]]-numli[v]-1),
    		SEG::query(1,1,n,dfn[top[v]]+numli[v],dfn[top[v]]+cntli[top[v]]-1,1)-numli[v])+dep[u]-dep[v]);
    	}
    	return ret;
    }
    void init(){
    	initdep(1,0);
    	initdfn(1,1);
    }
    
    int main(){
    	int Q;
    	scanf("%d%d",&n,&Q);
    	for(int i=1;i<n;i++){
    		int u,v;
    		scanf("%d%d",&u,&v);
    		add(u,v);
    		add(v,u);
    	}
    	init();
    	for(int i=1;i<=n;i++)dis[i]=INF;
    	change(1);
    	while(Q--){
    		int mo,x;
    		scanf("%d%d",&mo,&x);
    		if(mo==1){
    			change(x);
    		}
    		else{
    			printf("%d
    ",query(x));
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    AutoLayout动画
    实现毛玻璃效果
    合并静态库
    GCDAsyncSocket~
    iOS下URL编码
    OC多线程之GCD ----- 2
    堆和栈的区别
    Effective Objective-C 2.0重读笔记---2
    Android手机端抓包方法
    Android APK反编译
  • 原文地址:https://www.cnblogs.com/BlogOfchc1234567890/p/10423021.html
Copyright © 2011-2022 走看看