• [CLYZ2017]day6


    摆棋子

    image

    solution

    100分

    最大流

    \(s\)向第\(i\)行连一条容量为\(x_i\)的有向边;
    如果\((i,j)\)是空的,从第\(i\)行向第\(j\)列连一条容量为\(1\)的有向边;
    从第\(j\)列向\(t\)连一条容量为\(y_i\)的有向边.
    如果跑了\((i,j)\)这条边,表示选了\((i,j)\)这个点,即省了\(1\)花费.
    \(ans=\sum{x_i}+\sum{y_i}-maxflow\).

    #include<cmath>
    #include<ctime>
    #include<queue>
    #include<stack>
    #include<cstdio>
    #include<vector>
    #include<cstring>
    #include<cstdlib>
    #include<iostream>
    #include<algorithm>
    #define K 110
    #define N 210
    #define M 20410
    using namespace std;
    struct graph{
    	int nxt,to,f;
    }e[M];
    int x[K],y[K],g[N],dep[N],n,m,k,s,t,ans,inf,cnt=1;
    bool a[K][K];queue<int> q;
    inline void addedge(int x,int y,int f){
    	e[++cnt].nxt=g[x];g[x]=cnt;e[cnt].to=y;e[cnt].f=f;
    } 
    inline void adde(int x,int y,int f){
    	addedge(x,y,f);addedge(y,x,0);
    }
    inline bool bfs(int u){
    	memset(dep,0,sizeof(dep));
    	q.push(u);dep[u]=1;
    	while(!q.empty()){
    		u=q.front();q.pop();
    		for(int i=g[u];i;i=e[i].nxt)
    			if(e[i].f>0&&!dep[e[i].to]){
    				q.push(e[i].to);
    				dep[e[i].to]=dep[u]+1;
    			}
    	}
    	return dep[t];
    }
    inline int dfs(int u,int f){
    	if(u==t) return f;
    	int ret=0;
    	for(int i=g[u],d;i&&f;i=e[i].nxt)
    		if(e[i].f>0&&dep[e[i].to]>dep[u]){
    			d=dfs(e[i].to,min(e[i].f,f));
    			f-=d;ret+=d;e[i].f-=d;e[i^1].f+=d;
    		}
    	if(!ret) dep[u]=-1;
    	return ret; 
    }
    inline bool chk(){
    	for(int i=1,t;i<=n;++i){
    		t=0;
    		for(int j=1;j<=m;++j)
    			if(!a[i][j]) ++t;
    		if(t<x[i]) return false; 
    	}
    	
    	for(int j=1,t;j<=m;++j){
    		t=0;
    		for(int i=1;i<=n;++i)
    			if(!a[i][j]) ++t;
    		if(t<y[j]) return false; 
    	}
    	return true;
    }
    inline int dinic(){
    //	printf("")
    	int ret=0;
    	while(bfs(s))
    		ret+=dfs(s,inf);
    	return ret;
    }
    inline void Aireen(){
    	scanf("%d%d%d",&n,&m,&k);
    	s=n+m+1;t=s+1;inf=n*m;
    	for(int i=1;i<=n;++i){
    		scanf("%d",&x[i]);
    		adde(s,i,x[i]);ans+=x[i];
    	}
    	for(int j=1;j<=m;++j){
    		scanf("%d",&y[j]);
    		adde(j+n,t,y[j]);ans+=y[j];
    	}
    	for(int i=1,p,q;i<=k;++i){
    		scanf("%d%d",&p,&q);a[p][q]=true;
    	}
    	if(!chk()){
    		puts("No Solution");return;
    	}
    	for(int i=1;i<=n;++i)
    		for(int j=1;j<=m;++j)
    			if(!a[i][j]) adde(i,j+n,1);
    	printf("%d\n",ans-dinic());
    }
    int main(){
    	freopen("chessman.in","r",stdin);
    	freopen("chessman.out","w",stdout);
    	Aireen();
    	fclose(stdin);
    	fclose(stdout);
    	return 0;
    }
    

    有上下界的网络流

    \(s\)向第\(i\)行连一条容量为\([x_i,m]\)的有向边;
    如果\((i,j)\)是空的,从第\(i\)行向第\(j\)列连一条容量为\([0,1]\)的有向边;
    从第\(j\)列向\(t\)连一条容量为\([y_i,n]\)的有向边.
    跑最小可行流.

    #include<cmath>
    #include<ctime>
    #include<queue>
    #include<stack>
    #include<cstdio>
    #include<vector>
    #include<cstring>
    #include<cstdlib>
    #include<iostream>
    #include<algorithm>
    #define K 110
    #define N 210
    #define M 100010
    using namespace std;
    struct graph{
    	int nxt,to,f;
    }e[M];
    int g[N],ts[N],tt[N],dep[N],n,m,k,s,t,S,T,ans,inf,cnt=1;
    bool a[K][K];queue<int> q;
    inline void addedge(int x,int y,int f){
    	e[++cnt].nxt=g[x];g[x]=cnt;e[cnt].to=y;e[cnt].f=f;
    } 
    inline void adde(int x,int y,int f){
    	addedge(x,y,f);addedge(y,x,0);
    }
    inline void add(int x,int y,int l,int u){
    	tt[x]+=l;ts[y]+=l;adde(x,y,u-l);
    }
    inline bool bfs(int u){
    	memset(dep,0,sizeof(dep));
    	q.push(u);dep[u]=1;
    	while(!q.empty()){
    		u=q.front();q.pop();
    		for(int i=g[u];i;i=e[i].nxt)
    			if(e[i].f>0&&!dep[e[i].to]){
    				q.push(e[i].to);
    				dep[e[i].to]=dep[u]+1;
    			}
    	}
    	return dep[T];
    }
    inline int dfs(int u,int f){
    	if(u==T) return f;
    	int ret=0;
    	for(int i=g[u],d;i&&f;i=e[i].nxt)
    		if(e[i].f>0&&dep[e[i].to]>dep[u]){
    			d=dfs(e[i].to,min(e[i].f,f));
    			f-=d;ret+=d;e[i].f-=d;e[i^1].f+=d;
    		}
    	if(!ret) dep[u]=-1;
    	return ret; 
    }
    inline int dinic(){
    	int ret=0;
    	while(bfs(S))
    		ret+=dfs(S,inf);
    	return ret;
    }
    inline bool chk(){
    	for(int i=g[S];i;i=e[i].nxt)
    		if(!(i&1)&&e[i].f) return false;
    	return true;
    }
    inline void Aireen(){
    	scanf("%d%d%d",&n,&m,&k);
    	s=n+m+1;t=s+1;S=t+1;T=S+1;inf=n*m;
    	for(int i=1,x;i<=n;++i){
    		scanf("%d",&x);add(s,i,x,inf);
    	}
    	for(int j=1,y;j<=m;++j){
    		scanf("%d",&y);add(j+n,t,y,inf);
    	}
    	for(int i=1,x,y;i<=k;++i){
    		scanf("%d%d",&x,&y);a[x][y]=true;
    	}
    	for(int i=1;i<=n;++i)
    		for(int j=1;j<=m;++j)
    			if(!a[i][j]) add(i,j+n,0,1);
    	for(int i=1;i<=t;++i) 
    		if(ts[i]) adde(S,i,ts[i]);
    	for(int i=1;i<=t;++i) 
    		if(tt[i]) adde(i,T,tt[i]);
    	dinic();
    	adde(t,s,inf);
    	ans=dinic();
    	if(!chk()){
    		puts("No Solution");
    		return;
    	}
    	printf("%d\n",ans);
    }
    int main(){
    	freopen("chessman.in","r",stdin);
    	freopen("chessman.out","w",stdout);
    	Aireen();
    	fclose(stdin);
    	fclose(stdout);
    	return 0;
    }
    

    旅行路线

    image

    solution

    100分

    因为是单向边,问题可转化为求一棵字典树的所有节点到根节点的路径能组成多少个不同的字符串.
    利用倍增\(hash\)这棵树,将所有到根路径利用倍增排序.求出相邻两个路径的\(LCP\)即可.

    #include<cmath>
    #include<ctime>
    #include<queue>
    #include<stack>
    #include<cstdio>
    #include<vector>
    #include<cstring>
    #include<cstdlib>
    #include<iostream>
    #include<algorithm>
    #define K 20
    #define N 100005
    using namespace std;
    typedef long long ll;
    struct graph{
    	int nxt,to;
    }e[N<<1];
    int f[N][K],d[N],g[N],s[N],id[N],dep[N],n,top,cnt;
    ll ha[N][K],h[K],ans;
    inline void addedge(int x,int y){
    	e[++cnt].nxt=g[x];g[x]=cnt;e[cnt].to=y;
    }
    inline void dfs(int u){
    	s[++top]=u;dep[u]=1;
    	while(top){
    		u=s[top--];
    		if(u==1) ha[u][0]=d[u];
    		else for(int i=1,k;i<K;++i){
    			k=f[u][i-1];
    			f[u][i]=f[k][i-1];
    			if((1<<i)<=dep[u])
    				ha[u][i]=ha[u][i-1]+h[i-1]*ha[k][i-1];
    		}
    		for(int i=g[u],c;i;i=e[i].nxt)
    			if(!dep[c=e[i].to]){
    				s[++top]=c;
    				dep[c]=dep[u]+1;
    				f[c][0]=u;ha[c][0]=d[c];
    			}
    	}
    }
    inline bool cmp(int x,int y){
    	for(int i=K-1;i>=0;--i)
    		if(ha[x][i]&&ha[x][i]==ha[y][i]){
    			x=f[x][i];y=f[y][i];
    		}
    	return ha[x][0]<ha[y][0];
    }
    inline int func(int x,int y){
    	int ret=0;
    	for(int i=K-1;i>=0;--i)
    		if(ha[x][i]&&ha[x][i]==ha[y][i]){
    			x=f[x][i];y=f[y][i];ret+=(1<<i);
    		}
    	return ret;
    }
    inline void Aireen(){
    	scanf("%d",&n);
    	for(int i=1,j,k;i<n;++i){
    		scanf("%d%d",&j,&k);
    		addedge(k,j);addedge(j,k);++d[j];++d[k];
    	}
    	h[0]=232333ll;
    	for(int i=1;i<K;++i)
    		h[i]=h[i-1]*h[i-1];
    	dfs(1);
    	for(int i=1;i<=n;++i)
    		id[i]=i;
    	sort(id+1,id+1+n,cmp);
    	for(int i=1;i<=n;++i)
    		ans+=(ll)(dep[i]);
    	for(int i=1;i<n;++i)
    		ans-=(ll)(func(id[i],id[i+1]));
    	printf("%lld\n",ans);
    }
    int main(){
    	freopen("route.in","r",stdin);
    	freopen("route.out","w",stdout);
    	Aireen();
    	fclose(stdin);
    	fclose(stdout);
    	return 0;
    }
    

    流浪者

    image

    solution

    100分

    \(f[i][j]\)表示到达第\(i\)个障碍时,一共经过了\(j\)个障碍.

    \(f[i][j]=C_{x_i+y_i-2}^{x_i-1}-\sum_{k=1}^{i-1}\sum_{x_k\leq{x_i},y_k\leq{y_i}}f[k][j]\times{C_{x_i-x_k+y_i-y_k}^{x_i-x_k}}-\sum_{k=1}^{j-1}f[i][k]\).

    也就是总方案数\(-\)走过来\(>j\)个的方案数\(-\)走过来\(<j\)个的方案数.

    因为只会有\(\lceil\frac{s}{2}\rceil\)个不同的情况,所以只需求经过\(i(0\leq{i}\leq\lceil\frac{s}{2}\rceil)\)个障碍的方案数,剩下的方案贡献都是\(1\).

    \((1,1),(n,m)\)的障碍情况特判即可.

    #include<cmath>
    #include<ctime>
    #include<queue>
    #include<stack>
    #include<cstdio>
    #include<vector>
    #include<cstring>
    #include<cstdlib>
    #include<iostream>
    #include<algorithm>
    #define N 2005
    #define M 200001
    #define K 1000000007ll
    #define min(x,y) (x<y?x:y)
    #define max(x,y) (x>y?x:y)
    using namespace std;
    typedef long long ll;
    struct point{
    	int x,y;
    }a[N];
    int n,m,k,s,t;
    ll f[N][25],fac[M],rev[M],ans,cnt;
    inline ll po(ll x,int k){
    	ll ret=1ll;
    	while(k){
    		if(k&1) ret=ret*x%K;
    		x=x*x%K;k>>=1;
    	}
    	return ret;
    }
    inline ll c(int n,int m){
    	if(n<m) return 0;
    	return fac[n]*rev[n-m]%K*rev[m]%K;
    }
    inline ll tot(int n,int m){
    	return c(n+m,m);
    }
    inline ll hhh(int n,int m){
    	n+=m;
    	return rev[n]*fac[n-m]%K*fac[m]%K;
    }
    inline bool cmp(point x,point y){
    	if(x.x!=y.x) return x.x<y.x;
    	return x.y<y.y;
    }
    inline void Aireen(){
    	fac[0]=fac[1]=1ll;
    	for(int i=2;i<M;++i)
    		fac[i]=1ll*fac[i-1]*i%K;
    	rev[0]=rev[1]=1ll;
    	rev[M-1]=po(fac[M-1],(int)(K)-2);
    	for(int i=M-2;i>1;--i)
    		rev[i]=1ll*rev[i+1]*(i+1ll)%K;
    	scanf("%d%d%d%d",&n,&m,&k,&s);
    	for(int i=1;i<=k;++i)
    		scanf("%d%d",&a[i].x,&a[i].y);
    	sort(a+1,a+1+k,cmp);
    	while((1<<t)<s) ++t;
    	int tmp=0;
    	if(a[1].x==1&&a[1].y==1) 
    		f[1][1]=1,tmp=1;
    	else{
    		f[0][0]=1;
    		a[0]=(point){1,1};
    	}
    	for(int i=tmp+1;i<=k;++i){
    		for(int j=1;j<=t;++j){
    			f[i][j]=tot(a[i].x-1,a[i].y-1);
    			for(int l=tmp;l<i;++l)
    				if(a[l].y<=a[i].y)
    					f[i][j]=(f[i][j]-f[l][j]*tot(a[i].x-a[l].x,a[i].y-a[l].y)%K+K)%K;
    			for(int l=1;l<j;++l)
    					f[i][j]=(f[i][j]-f[i][l]+K)%K;
    		}
    	}
    	if(a[k].x==n&&a[k].y==m){
    		for(int i=0;i<=t;++i){
    			ans=(f[k][i]*s+ans)%K;
    			cnt=(f[k][i]+cnt)%K;
    			s=(s+1)>>1;
    		}
    	}
    	else{
    		a[++k].x=n;a[k].y=m;
    		for(int j=0;j<=t;++j){
    			f[k][j]=tot(a[k].x-1,a[k].y-1);
    			for(int l=tmp;l<k;++l)
    				f[k][j]=(f[k][j]-f[l][j+1]*tot(a[k].x-a[l].x,a[k].y-a[l].y)%K+K)%K;
    			for(int l=0;l<j;++l)
    				f[k][j]=(f[k][j]-f[k][l]+K)%K;
    		}
    		for(int i=0;i<=t;++i){
    			ans=(f[k][i]*s+ans)%K;
    			cnt=(f[k][i]+cnt)%K;
    			s=(s+1)>>1;
    		}
    	}
    	ans=(ans+tot(n-1,m-1)-cnt+K)%K;
    	printf("%lld\n",ans*hhh(n-1,m-1)%K);
    }
    int main(){
    	freopen("rover.in","r",stdin);
    	freopen("rover.out","w",stdout);
    	Aireen();
    	fclose(stdin);
    	fclose(stdout);
    	return 0;
    }
    
  • 相关阅读:
    开源博客平台WordPress十岁啦!
    (转载)C# Attribute 用法备忘
    hibernate入门
    Hibernate对象关系映射基础
    struts2UI标签
    struts2文件上传2(多文件)
    struts2验证(手工)
    通过修改注册表改变txt文件的默认打开方式
    struts2验证(XML)
    Struts国际化
  • 原文地址:https://www.cnblogs.com/AireenYe/p/CLYZ2017day6.html
Copyright © 2020-2023  润新知