20161103的考试】树上链max,数列瞎搞搞,模拟

20 篇文章 0 订阅
14 篇文章 0 订阅

怎么觉得天天都有模拟题啊QAQ

……T1T2我比大爷们写的都多了个log【2333

T1写完敲了个对拍,然而一拍就WA……搞了半天发现是暴力求lca写错了233333

……其实T1写了一个小时的原因是……正解十多分钟,暴力+datamaker十多分钟,……wa了找错+发现是暴力写错+改暴力……半个小时过去了233333


T1:

题意:n个节点的树,m次查询,求节点x和y之间的最长路径是否大于c【可以转换成这个意思……】

思路:…………我特么……写了个链剖序线段树233333,其实没有修改的话直接维护一下就好了……在不在同一条链上的时候,走的路径肯定是这条链的前缀,于是O(1)得到答案,最后那一节再用线段树瞎搞搞,单次查询是O(log(n))的,比起log方快到不知道哪里去了x

代码(O(n*log^2(n)))

#include<bits/stdc++.h>
#define MAXN 100005
using namespace std;	int n,m;
const long long INF = 0x3f3f3f3f3f3f3f3f;
struct t1{
	int to,nxt,lth;
}edge[MAXN<<1];	int cnt_edge=0;
int fst[MAXN];
inline void addedge(int x,int y,int lth){
	edge[++cnt_edge].to=y;
	edge[cnt_edge].nxt=fst[x];
	edge[cnt_edge].lth=lth;
	fst[x]=cnt_edge;
	
	edge[++cnt_edge].to=x;
	edge[cnt_edge].nxt=fst[y];
	edge[cnt_edge].lth=lth;
	fst[y]=cnt_edge;
}

int root;
int fth[MAXN],top[MAXN],son[MAXN],siz[MAXN];
int dpt[MAXN];

int val[MAXN];
int dfn[MAXN],idf[MAXN],cnt_dfs=0;

void dfs1(int now){
	siz[now]=1;
	for(register int tmp=fst[now];tmp;tmp=edge[tmp].nxt){
		int aim=edge[tmp].to;
		if(aim==fth[now])	continue;
		fth[aim] = now;
		dpt[aim] = dpt[now] + 1;
		val[aim] = edge[tmp].lth;
		dfs1(aim);
		siz[now] += siz[aim];
		if(siz[aim] >= siz[son[now]])
			son[now] = aim;
	}
}

void dfs2(int now,int tp){
	top[now] = tp;
	dfn[now] = ++cnt_dfs;
	idf[cnt_dfs] = now;
	if(son[now])	dfs2(son[now],tp);
	for(register int tmp=fst[now];tmp;tmp=edge[tmp].nxt){
		int aim = edge[tmp].to;
		if(aim == fth[now] || aim == son[now])	continue;
		dfs2(aim,aim);
	}
}

inline int lca(int u,int v){
	while(top[u]^top[v])
		(dpt[fth[top[u]]] < dpt[fth[top[v]]])?
			v = fth[top[v]] : u = fth[top[u]];
	return dpt[u]<dpt[v] ? u:v;
}

//===================================================================
int dt[MAXN<<2];
void build(int now,int l,int r){
	if(l==r)	return void(dt[now] = val[idf[l]]);
	int mid = (l+r)>>1;
	build(now<<1,l,mid);
	build(now<<1|1,mid+1,r);
	dt[now] = max(dt[now<<1],dt[now<<1|1]);
}

int inqry(int now,int l,int r,int L,int R){
	if(L<=l&&r<=R)
		return dt[now];
	int mid=(l+r)>>1;
	int tmp=0;
	if(L<=mid)	tmp=inqry(now<<1,l,mid,L,R);
	if(mid<R)	tmp = max(tmp,inqry(now<<1|1,mid+1,r,L,R));
	return tmp;
}

int get_delta(int u,int v,int c){
	int tmp = 0;
	
//	printf("lca ( %d , %d ) = ",u,v);
	
	while(top[u]^top[v]){
		if( dpt[fth[top[u]]] < dpt[fth[top[v]]]){
			tmp = max(tmp,inqry(1,1,n,dfn[top[v]],dfn[v]));
			v = fth[top[v]];
		}
		else{
			tmp = max(tmp,inqry(1,1,n,dfn[top[u]],dfn[u]));
			u = fth[top[u]];
		}
	}
	if(dpt[u] < dpt[v])	tmp = max(tmp,inqry(1,1,n,dfn[son[u]],dfn[v]));
	else	if(dpt[u] > dpt[v]) tmp = max(tmp,inqry(1,1,n,dfn[son[v]],dfn[u]));
	
//	printf("%d\n",dpt[u]<dpt[v]?u:v);
	
	return tmp-c;
}
//===============================================================================

long long ans=0;
int id=-1;

int read_x,read_y,read_c;
int main(){
	
	srand(20000218);
	
	freopen("rebuild.in","r",stdin);
	freopen("rebuild.out","w",stdout);
	
	scanf("%d%d",&n,&m);
	if(!n)	return puts("I'm angry!");
	
	root = rand()%n+1;
	
	for(register int i=1;i<n;++i)
		scanf("%d%d%d",&read_x,&read_y,&read_c),addedge(read_x,read_y,read_c);
	
	dpt[root]=1;
	dfs1(root);
	dfs2(root,root);
	build(1,1,n);
	
	for(register int i=1;i<=m;++i){
		scanf("%d%d%d",&read_x,&read_y,&read_c);
		int kk = get_delta(read_x,read_y,read_c);
		if( kk > ans )
			ans = kk,id=i;
			
//		printf("id = %d    dlt = %d\n",i,kk);				
			
	}
	
	if(!~id)	puts("I'm angry!");
	else	printf("%d",id);
	return 0;
}

T2

题意:有个1到n的区间,m次操作,每次对(l,r)的区间增加一个数,只记录每个节点的前五个值

思路:……线段树套vector啊不怂……反正随便搞………………

           然而大爷们怎么都跑得这么快QwQ

           哦好嘛……嗯考虑一下,用链表维护这个序列,每次操作暴力地加上这个值,如果发现当前节点记录的值达到了5就直接从链表中删除这个点

           于是每个节点最多被访问5次,均摊是O(n)的,常数是5

代码(O(n*log(n))的)

#include<bits/stdc++.h>
#define MAXN 100005
using namespace std;	int n,m;

struct t1{
	int siz;
	int rec[5];
	void push(int x){rec[siz++]=x;}
	t1():siz(0){rec[0]=rec[1]=rec[2]=rec[3]=rec[4]=0;}
};

t1 dt[MAXN<<2],tag[MAXN<<2];

inline void pushdown(int now){
	for(int i=0;i<tag[now].siz;++i){
		if(dt[now<<1].siz < 5)
			dt[now<<1].push(tag[now].rec[i]),tag[now<<1].push(tag[now].rec[i]);
		if(dt[now<<1|1].siz < 5)
			dt[now<<1|1].push(tag[now].rec[i]),tag[now<<1|1].push(tag[now].rec[i]);
	}
	tag[now].siz=0;
}

void modify(int now,int l,int r,int L,int R,int v){
	if(L<=l&&r<=R){
		if(dt[now].siz>=5)	return ;
		dt[now].push(v);
		tag[now].push(v);
		return ;
	}
	int mid=(l+r)>>1;
	pushdown(now);
	if(L<=mid)	modify(now<<1,l,mid,L,R,v);
	if(mid<R)	modify(now<<1|1,mid+1,r,L,R,v);
}

void print(int now,int l,int r){
	if(l==r){
		for(int i=0;i<dt[now].siz;++i)
			printf("%d ",dt[now].rec[i]);
		puts("");
		return ;
	}
	pushdown(now);
	int mid=(l+r)>>1;
	print(now<<1,l,mid);
	print(now<<1|1,mid+1,r);
}

int read_x,read_y;
int main(){
	freopen("present.in","r",stdin);
	freopen("present.out","w",stdout);

	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;++i){
		scanf("%d%d",&read_x,&read_y);
		modify(1,1,n,read_x,read_y,i);
	}	
	print(1,1,n);
	return 0;
}

T3

题面:………………德州扑克规则,(五十二张扑克牌去掉大小王)知道两个人的手牌和三张底牌,问赢的概率(平局算负)

思路:md模拟题,淦啊模拟题…………嗯上午哼着ギリギリEYE敲了10k代码发现还没写check……估计写完就是15k的量了23333

          总之,这道题是只要写完不管多暴力都能过的那种23333

          FTC大爷表示,每次枚举剩下的两张底牌,以及两个人选择的五张牌(相当于是枚举不选的那两张),然后check。

                    check的时候先按照每个值出现的次数排序,于是大部分情况被判掉了,同花这个直接判一下就好

代码:【woc我要死了我是谁我在哪儿……】

#include<bits/stdc++.h>
using namespace std;	char read_s[5];

struct rec_card_num{
	int cnt,num;
	bool operator < (const rec_card_num ano) const{
		return cnt==ano.cnt? num > ano.num : cnt > ano.cnt;
	}
}rec[15];

struct card{
	int col,num;
	card(){}
	card(int col,int num):col(col),num(num){}
	card(char *s){
		if((*s)=='S')	col=0;
		if((*s)=='H')	col=1;
		if((*s)=='D')	col=2;
		if((*s)=='C')	col=3;
		++s;
		if(isdigit(*s))	num=*s-'0';
		else{
			if(*s=='T')	num=10;
			if(*s=='J')	num=11;
			if(*s=='Q')	num=12;
			if(*s=='A')	num=14;
			if(*s=='K')	num=13;
		}
	}
	bool operator < (const card ano)const{
		return num==ano.num? col < ano.col: num < ano.num;
	}
	bool operator == (const card ano) const{
		return col==ano.col && num==ano.num;
	}
};

struct YJQ{
	card c[7];
	int rank,hash_val;
	int tmp_rank,tmp_hash;
	
	bool noo(card x){
		for(int i=0;i<5;++i)
			if(c[i]==x)	return 0;
		return 1;
	}
	
	card cur[5];
	int cnt_cur;
	
	void get_level_and_hash(){
		for(int i=0;i<15;++i)	rec[i].num=i,rec[i].cnt=0;
		for(int i=0;i<5;++i)
			++rec[cur[i].num].cnt;
		sort(rec,rec+15);
		if(rec[0].cnt==4){
			tmp_rank = 3;
			tmp_hash = rec[0].num * 15 + rec[1].num;
		}	
		if(rec[0].cnt==3 && rec[1].cnt==2){
			tmp_rank = 4;
			tmp_hash = rec[0].num * 15 + rec[1].num;
		}
		if(rec[0].cnt==3 && rec[1].cnt==1){
			tmp_rank = 7;
			tmp_hash = rec[0].num * 15 * 15 + rec[1].num * 15 + rec[2].num;
		}
		if(rec[0].cnt==2 && rec[1].cnt==2){
			tmp_rank = 8;
			tmp_hash = rec[0].num * 15 * 15 + rec[1].num * 15 + rec[2].num;
		}
		if(rec[0].cnt==2 && rec[1].cnt==1){
			tmp_rank = 9;
			tmp_hash = rec[0].num * 15 * 15 * 15
				     + rec[1].num * 15 * 15
				     + rec[2].num * 15
				     + rec[3].num ;
		}
		if(rec[0].cnt==1){
			int tong = 1;
			for(int i=1;i<5;++i)
				if(cur[i].col ^ cur[0].col)
					tong = 0;
			int shun = 1;
			for(int i=0;i<4;++i)
				if(rec[i+1].num ^ (rec[i].num-1))
					shun=0;
			if(rec[0].num==14 && rec[1].num==5 && rec[2].num==4 &&
			   rec[3].num==3 &&rec[4].num==2)
					shun=1;
			if(shun){
				tmp_rank = tong ? 2 : 6 ;
				tmp_hash = (rec[0].num==14 && rec[1].num==5)?5:rec[0].num;
			}
			else{
				tmp_rank = tong ? 5 : 10;
				tmp_hash = rec[0].num * 15 * 15 * 15 * 15
						 + rec[1].num * 15 * 15 * 15
						 + rec[2].num * 15 * 15
						 + rec[3].num * 15
						 + rec[4].num ;
			}
		}
	}
	
	void get_max(){
		for(int i=0;i<7;++i)
			for(int j=i+1;j<7;++j){
				cnt_cur=0;
				for(int k=0;k<7;++k)
					if((k^i)&&(k^j))
						cur[cnt_cur++]=c[k];
				get_level_and_hash();
				if(tmp_rank < rank){
					rank = tmp_rank;
					hash_val = tmp_hash;
				}
				else{
					if(tmp_rank == rank){
						if( tmp_hash > hash_val)
							hash_val = tmp_hash;
					}
				}
			}
	}
	
	void print(){
		for(int i=0;i<7;++i)
			printf("col = %d     num = %d\n",c[i].col,c[i].num);
		puts("");
	}
}fr,wa;

int main(){
	freopen("interview.in","r",stdin);
	freopen("interview.out","w",stdout);	
	
	scanf("%s",read_s);
	while(read_s[0]^'#'){
		fr.c[0]=card(read_s);
		scanf("%s",read_s);
		fr.c[1]=card(read_s);
		scanf("%s",read_s);
		wa.c[0]=card(read_s);
		scanf("%s",read_s);
		wa.c[1]=card(read_s); 
		
		scanf("%s",read_s);
		fr.c[2]=wa.c[2]=card(read_s);
		scanf("%s",read_s);
		fr.c[3]=wa.c[3]=card(read_s);
		scanf("%s",read_s);
		fr.c[4]=wa.c[4]=card(read_s);
		
		int shang = 0,xia = 0;
		
		for(int xi=0;xi<4;++xi)
			for(int xj=2;xj<=14;++xj)
				for(int yi=0;yi<4;++yi)
					for(int yj=2;yj<=14;++yj){
						card x(xi,xj),y(yi,yj);
						if(x < y && fr.noo(x) && fr.noo(y) && wa.noo(x) && wa.noo(y)){
							fr.c[5]=wa.c[5]=x;
							fr.c[6]=wa.c[6]=y;
							++xia;
							fr.rank=11,wa.rank=11;
							fr.get_max();
							wa.get_max();

						
//							printf("rank zhangzhe = %d\n",fr.rank);
//							printf("rank wallace = %d\n",wa.rank);


							if(fr.rank < wa.rank){
								++shang;
											
//								printf("%d\n",xia);
//								puts("HA");
//								fr.print();
//								puts("WA");
//								wa.print();
							}
							else{
								if(fr.rank == wa.rank)
									if(fr.hash_val > wa.hash_val){
										++shang;
										
//										printf("%d\n",xia);
//										puts("HA");
//										fr.print();
//										puts("WA");
//										wa.print();
									}
							}
						}
					}
		printf("%.3f\n",(double)shang/xia);
		scanf("%s",read_s);
	}
} 



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值