zoukankan      html  css  js  c++  java
  • [Contest on 2021.9.2] 读不懂题啊!

    ( ext{Knockout})

    原题:( ext{Boomerang Tournament})

    题目描述

    (n) 支队伍((n)(2^k))进行淘汰赛,已知两两胜负关系。在每种对阵情况中,请计算出第 (i) 支队伍的最好名次和最劣名次。

    (1le T,nle 16)(G_{i,i}=0),对于所有 (i eq j),都有 (G_{i,j} eq G_{j,i})


    需要注意名次的计算方式。将所有队伍按胜出场数从大到小排序,比如有两队并列第三,那么 下一种 场数的队伍就应该是第五名。

    ( m sb) 博主观察了老久的样例都没看懂…

    解法

    很玄学的是,我随机化了 (10^5) 次就拿到了 ( m 100pts)代码戳这。但是我算了算,本质不同的排列是 (frac{16!}{2^8cdot 2^4cdot 2^2 cdot 2}) 的?就很离谱。

    (dp_{s,i}) 是在 (s) 的集合中,(i) 是否能成为优胜者,其中 (s) 一定是 (2) 的幂。转移是比较简单的,我主要是分析一下复杂度。

    考虑有四个 (1) 的集合共有 (inom{16}{4}=1820) 个,有八个 (1) 的集合共有 (inom{16}{8}=12870) 个,其余的都比较小了,不妨只分析 (siz=16,8) 的循环。

    这样大概是 (mathcal O((1cdot 12870cdot 8^2/2+12870cdot inom{8}{4}cdot 4^2/2)cdot T)),还是蛮稳的。

    代码

    #include <cstdio>
    #define print(x,y) write(x),putchar(y)
    
    template <class T> 
    inline T read(const T sample) {
    	T x=0; char s; bool f=0;
    	while((s=getchar())>'9' or s<'0')
    		f|=(s=='-');
    	while(s>='0' and s<='9') 
    		x=(x<<1)+(x<<3)+(s^48),
    		s=getchar();
    	return f?-x:x;
    } 
    
    template <class T> 
    inline void write(const T x) {
    	if(x<0) {
    		putchar('-');
    		write(-x);
    		return;
    	}
    	if(x>9) write(x/10);
    	putchar(x%10^48);
    }
    
    #include <vector>
    #include <cstring>
    #include <iostream>
    using namespace std;
    
    const int maxn=20;
    
    int n,g[maxn][maxn];
    int dp[1<<16][17];
    int mx[maxn],mn[maxn];
    vector <int> mask[17];
    
    void init() {
    	for(int i=0;i<(1<<16);++i) {
    		int t=__builtin_popcount(i);
    		if(((t-1)&t)==0)
    			mask[t].push_back(i);
    	}
    }
    
    int lowbit(int x) {
    	return x&-x;
    }
    
    int main() {
    	freopen("knock.in","r",stdin);
    	freopen("knock.out","w",stdout);
    	int fk=0;
    	init();
    	for(int T=read(9);T;--T) {
    		memset(dp,0,sizeof dp);
    		n=read(9);
    		for(int i=0;i<n;++i) {
    			mx[i]=0,mn[i]=n;
    			dp[1<<i][i]=1;
    			for(int j=0;j<n;++j)
    				g[i][j]=read(9);
    		}
    		printf("Case #%d:
    ",++fk);
    		int dep=1;
    		for(int siz=2;siz<=n;siz<<=1,++dep)
    			for(int uu=0;uu<mask[siz].size();++uu) {
    				int U=mask[siz][uu];
    				if(U>=(1<<n)) break;
    				for(int ss=0;ss<mask[siz>>1].size();++ss) {
    					int S=mask[siz>>1][ss];
    					if((S&U)!=S) continue;
    					int T=U^S;
    					if(S>T) continue;
    					int s=S;
    					while(s) {
    						int i=__builtin_ctz(s);
    						s-=lowbit(s);
    						if(!dp[S][i]) continue;
    						int t=T;
    						while(t) {
    							int j=__builtin_ctz(t);
    							t-=lowbit(t);
    							if(!dp[T][j]) continue;
    							if(g[i][j]) {
    								dp[U][i]=1;
    								mx[i]=max(mx[i],dep);
    								mn[j]=min(mn[j],dep-1);
    							}
    							else {
    								dp[U][j]=1;
    								mx[j]=max(mx[j],dep);
    								mn[i]=min(mn[i],dep-1);
    							}
    						}
    					}
    				}
    			}
    		--dep;
    		for(int i=0;i<n;++i) {
    			int a=(mx[i]==dep)?0:(1<<(dep-mx[i]-1));
    			int b=(mn[i]>=dep)?0:(1<<(dep-mn[i]-1));
    			printf("%d %d
    ",a+1,b+1);
    		}
    	}
    	return 0;
    }
    

    ( ext{[ZJOI 2012] })小蓝的好友

    解法

    首先转化成一条鱼都没有的矩形有多少个。

    考虑添加一条与 (x) 轴平行的扫描线,从上往下移,那么扫描线以上的部分可以形成一个柱状图(遇见鱼 ((x,y)) 后将经过 (x) 的柱高度置为 (0))。

    对于固定的柱状图,我们可以以 (x)( m key),高度为 ( m val) 建立一棵笛卡尔树。对于每个宽为 (w),长为 (h) 的完整矩形,内部矩形计算公式是 (frac{w(w+1)}{2}cdot h)(相当于最左边的 (x)(x,x+1,...,x+w-1) 配对,依此类推)。单次计算是 (mathcal O(n)) 的。

    如何优化?考虑每次往下移扫描线,所有柱高度加一,遇到鱼时柱高度变为 (0),而且还要维护笛卡尔树。用 ( m treap) 啊!

    当某个柱高度变为 (0) 时,( m val) 改变导致堆的条件不满足,所以需要 split() 一下。因为鱼是随机的,所以是 (mathcal O(nlog n)) 的。

    代码

    #include <cstdio>
    #define print(x,y) write(x),putchar(y)
    
    template <class T> 
    inline T read(const T sample) {
    	T x=0; char s; bool f=0;
    	while((s=getchar())>'9' or s<'0')
    		f|=(s=='-');
    	while(s>='0' and s<='9') 
    		x=(x<<1)+(x<<3)+(s^48),
    		s=getchar();
    	return f?-x:x;
    } 
    
    template <class T> 
    inline void write(const T x) {
    	if(x<0) {
    		putchar('-');
    		write(-x);
    		return;
    	}
    	if(x>9) write(x/10);
    	putchar(x%10^48);
    }
    
    #include <algorithm>
    using namespace std;
    typedef long long ll;
    
    const int maxn=100005;
    
    ll S(int n) {
    	return 1ll*n*(n+1)/2;
    }
    
    int r,c,n;
    struct fish {
    	int x,y;
    	
    	bool operator < (const fish &t) const {
    		return y<t.y;
    	}
    } s[maxn];
    struct fhq_treap {
    	int idx,rt;
    	struct node {
    		int h,ls,rs,siz,la;
    		ll ans;
    	} t[maxn];
    	
    	int NewNode(int H) {
    		t[++idx].siz=1;
    		t[idx].h=H;
    		return idx;
    	}
    	
    	void add(int o,int k) {
    		if(!o) return;
    		t[o].la+=k;
    		t[o].h+=k;
    	}
    	
    	void pushDown(int o) {
    		if(!o or !t[o].la)
    			return;
    		add(t[o].ls,t[o].la);
    		add(t[o].rs,t[o].la);
    		t[o].la=0;
    	}
    	
    	void pushUp(int o) {
    		if(!o) return;
    		t[o].ans=0;
    		t[o].siz=t[t[o].ls].siz+t[t[o].rs].siz+1;
    		if(t[o].ls)
    			t[o].ans+=t[t[o].ls].ans+S(t[t[o].ls].siz)*(t[t[o].ls].h-t[o].h);
    		if(t[o].rs)
    			t[o].ans+=t[t[o].rs].ans+S(t[t[o].rs].siz)*(t[t[o].rs].h-t[o].h);
    	}
    	
    	void split(int o,int k,int &x,int &y) {
    		if(!o) x=y=0;
    		else {
    			pushDown(o);
    			if(t[t[o].ls].siz+1<=k) {
    				x=o;
    				split(t[o].rs,k-t[t[o].ls].siz-1,t[o].rs,y);
    			}
    			else {
    				y=o;
    				split(t[o].ls,k,x,t[o].ls);
    			}
    			pushUp(o);
    		}
    	}
    	
    	int merge(int x,int y) {
    		if(!x or !y)
    			return x|y;
    		if(t[x].h<t[y].h) {
    			pushDown(x);
    			t[x].rs=merge(t[x].rs,y);
    			pushUp(x);
    			return x;
    		}
    		else {
    			pushDown(y);
    			t[y].ls=merge(x,t[y].ls);
    			pushUp(y);
    			return y;
    		}
    	}
    	
    	void build(int n) {
    		for(int i=1;i<=n;++i)
    			rt=merge(rt,NewNode(0));
    	}
    } T;
    
    int main() {
    	r=read(9),c=read(9),n=read(9);
    	for(int i=1;i<=n;++i)
    		s[i]=(fish){read(9),read(9)};
    	T.build(r);
    	sort(s+1,s+n+1);
    	ll ans=S(r)*S(c);
    	int pos=1;
    	for(int i=1;i<=c;++i) {
    		T.add(T.rt,1);
    		while(pos<=n and s[pos].y==i) {
    			int cut=s[pos].x,a,b,c;
    			T.split(T.rt,cut-1,a,b);
    			T.split(b,1,b,c);
    			T.t[b].h=0;
    			T.rt=T.merge(T.merge(a,b),c);
    			++pos;
    		}
    		ans-=T.t[T.rt].ans+S(T.t[T.rt].siz)*T.t[T.rt].h;
    		// 最后还要计算最下面完整的一块
    	}
    	print(ans,'
    ');
    	return 0;
    }
    
  • 相关阅读:
    Spark SQL+day04笔记
    Spark 环境搭建
    海量数据处理 算法总结2
    Scala面试题 看过1
    HTML-table、form表单标签的介绍
    Java-CSS美化网页元素
    Java-BOM与DOM对象
    java-CSS盒子模型、浮动、定位
    java-基础面试题(2)
    Java-io流
  • 原文地址:https://www.cnblogs.com/AWhiteWall/p/15221161.html
Copyright © 2011-2022 走看看