WHU校赛2019(网络赛) 解题报告(CCNU_你们好强啊我们都是面包手) Apare_xzc

WHU校赛2019(网络赛) 解题报告

CCNU_你们好强啊我们都是面包手(xzc zx lj)

战况: 比赛时3题,排名57,现在5题了

题目链接: WHU校赛2019 <-戳这里


以下题目按难度顺序递增叙述

B.DrunkHamster
求两点之间距离的平方,签到题

/*
Apr/07/2019 13:49UTC+8	
CCNU_你们好强啊我们都是面包手	
B - DrunkHamster	
GNU C++17	Accepted	30 ms	0 KB
*/
#include <bits/stdc++.h>
#define For(i,a,b) for(register int i=(a);i<=(b);++i)
#define Rep(i,a,b) for(register int i=(a);i>=(b);--i)
#define Mst(a,b) memset(a,(b),sizeof(a))
#define LL long long
#define MP make_pair
#define pb push_back
using namespace std;
const int maxn = 1e5+100;
void solve(int x,int y)
{
	LL ans = (1ll*x*x+1ll*y*y);
	cout<<ans<<endl;
}
int main()
{
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    LL x,y,z;
	int T,n;
	cin>>T;
	int ca = 0;
	while(T--)
	{
		x = y = 0;
		scanf("%d",&n);
		For(i,0,n-1)
		{
			scanf("%I64d",&z);	
			if(i%4==0) y += z;
			else if(i%4==1) x+=z;
			else if(i%4==2) y-=z;
			else x-=z;
		}	
		printf("Case #%d:",++ca);
		solve(x,y);
	} 
    return 0;
}

E.Egnima
简单模拟,搞个map或者数组对应,比较字符串即可

/*
Apr/07/2019 14:03UTC+8	
CCNU_你们好强啊我们都是面包手	
E - Egnima	
GNU C++17	Accepted	31 ms	2100 KB
*/
#include <bits/stdc++.h>
#define For(i,a,b) for(register int i=(a);i<=(b);++i)
#define Rep(i,a,b) for(register int i=(a);i>=(b);--i)
#define Mst(a,b) memset(a,(b),sizeof(a))
#define LL long long
#define MP make_pair
#define pb push_back
using namespace std;
const int maxn = 1e6+100;
char a[] = "abcdefghijklmnopqrstuvwxyz";
char b[] = "22233344455566677778889999"; 
map<char,char> mp;
char num[maxn],str[maxn]; 
int LenNum;
bool ok()
{
	int len = strlen(str)-1;
	if(len!=LenNum) return false;
	For(i,0,len)
	{
		if(mp[str[i]]!=num[i]) return false;
	}
	return true;
}
int main()
{
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int len = strlen(a)-1;
    For(i,0,len)
    {
    	mp[a[i]] = b[i];
	}
	int T,n;
	cin>>T;
	int ca = 0;
	while(T--)
	{
		printf("Case #%d:\n",++ca);
		scanf("%s",num);
		LenNum = strlen(num)-1;
		scanf("%d",&n);
		For(ca,1,n)
		{
			scanf("%s",str);
			if(ok())
			{
				printf("Maybe..\n");
			}
			else
			{
				printf("How could that be possible?\n");
			}
		}
	} 
    return 0;
}

D.Dandelion

卡特兰数 C(m+n-1,n-1)-C(m+n-1,m-1))
预处理阶乘以及阶乘的逆元即可
打比赛的前一天我在牛客上写了道类似的题
感谢lj正确的公式,是我写呲了,忘记%mod+mod%mod,wa了一发,我的锅

/*
Apr/07/2019 14:44 UTC+8	
CCNU_你们好强啊我们都是面包手	
D - Dandelion	
GNU C++17  Accepted 62ms 31300 KB
*/
#include <bits/stdc++.h>
#define For(i,a,b) for(register int i=(a);i<=(b);++i)
#define Rep(i,a,b) for(register int i=(a);i>=(b);--i)
#define Mst(a,b) memset(a,(b),sizeof(a))
#define LL long long
#define MP make_pair
#define pb push_back
using namespace std;
const int maxn = 2e6+100;
const int mod = 1e9+7;
LL r[maxn];
LL fac[maxn];
LL fast_pow(LL a,LL b);
void init();
LL C(int n,int m); 
int main()
{
   // freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int T,m,n;
    init();
    cin>>T;
    while(T--)
    {
    	scanf("%d%d",&m,&n);
    	LL ans = ((C(m+n-1,max(m,n)-1)-C(m+n-1,min(m,n)-1))%mod+mod)%mod;
    	printf("%I64d\n",abs(ans));
	}
    
    return 0;
}


LL fast_pow(LL a,LL b)
{
	LL ans = 1;
	while(b)
	{
		if(b&1) ans = ans*a%mod;
		a = a*a%mod;
		b>>=1;	
	}
	return ans; 
} 
void init()
{
	fac[0] = 1;
	r[0] = 1;
	For(i,1,2000000) fac[i] = fac[i-1]*i%mod;
	r[2000000] = fast_pow(fac[2000000],mod-2);
	Rep(i,1999999,1)
		r[i] = r[i+1]*(i+1)%mod;
		
}
LL C(int n,int m)
{
	if(n<m||m<0) return 0;
	return fac[n]*r[m]%mod*r[n-m]%mod;
}

C.Store

题意:
n种货物
M x y:在第x天买了第y种货物
D x y: 查询在之前比x小的天数中卖过的货物>=y的最小值
1<=y<=n<=1e5 x<=1e9

思路:

  • 线段树,把x离散化,按x建立线段树,线段树每个节点开一个set,存这个区间里已经卖出去的y(货物种类)
  • 单点更新,区间查询
  • 这题还不难,但比赛的时候作为数据结构手的我去搞没做过的主席树了… 还是我的锅,不过今天上算法课写了一发,补出来了

/*
Apr/08/2019 15:43UTC+8	
CCNU_你们好强啊我们都是面包手	
C - Store	
GNU C++17  Accepted	794 ms  61900 KB
*/
#include <bits/stdc++.h>
#define For(i,a,b) for(register int i=(a);i<=(b);++i)
#define Rep(i,a,b) for(register int i=(a);i>=(b);--i)
#define Mst(a,b) memset(a,(b),sizeof(a))
#define LL long long
#define MP make_pair
#define pb push_back
using namespace std;
const int maxn = 2e5+3;
int a[maxn],p[maxn];
set<int>::iterator it;
struct SegmentTree{
	set<int> s; 
}tree[maxn<<2]; 
struct Question{
	char tp[2];
	int x,y;
}qu[maxn];
void update(int left,int right,int tx,int ty,int pos=1)
{
	tree[pos].s.insert(ty);
	if(left==right) return;
	int mid = (left+right)>>1;
	if(tx<=mid) update(left,mid,tx,ty,pos<<1);
	else update(mid+1,right,tx,ty,pos<<1|1);
}
int query(int left,int right,int qx,int qy,int ty,int pos=1) 
{
	if(left>qy || right<qx) 
	{
		return -1;	
	}
	if(qx<=left && right<= qy)
	{
		it = tree[pos].s.lower_bound(ty);
		if(it==tree[pos].s.end()) return -1;
		return *it;
	}
	int mid = (left+right)>>1; 
	int ansL = query(left,   mid,qx,qy,ty,pos<<1);
	int ansR = query(mid+1,right,qx,qy,ty,pos<<1|1);
	if(ansL==-1&&ansR==-1) return -1;
	else if(ansL==-1) return ansR;
	else if(ansR==-1) return ansL;
	return min(ansL,ansR);
}
int main()
{
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int n,Q;
    scanf("%d%d",&n,&Q); 
    For(i,1,Q)
    {
    	scanf("%s%d%d",qu[i].tp,&qu[i].x,&qu[i].y);
    	p[i] = qu[i].x;
	}
	sort(p+1,p+1+Q);
	int Maxx = 0;
	For(i,1,Q)
	{
		qu[i].x = lower_bound(p+1,p+1+Q,qu[i].x)-p;
		Maxx = max(Maxx,qu[i].x);
	}
	For(i,1,Q)
	{
		if(qu[i].tp[0]=='M') update(1,Maxx,qu[i].x,qu[i].y);
		else printf("%d\n",query(1,Maxx,1,qu[i].x,qu[i].y));
	}
    return 0;
}

F. Climb

  • 树上第K小板子题(不过这是第K大)
  • 今天学了一下,过了poj-2104,spoj-10628,学会了
  • LCA是我上上周学的,dfs+RMQ
  • 今天看卿爷和Y_Cl区间第K大的板子,感觉很好用
  • 于是根据主席树的原理,写出了树上第K大~
  • 这是我最近写的最长,开的数组最多的代码了
/*
Apr/08/2019 22:10UTC+8	
CCNU_你们好强啊我们都是面包手	
F - Climb	
GNU C++17 Accepted	1294 ms	59200 KB
*/
Apr/09/2019 06:22UTC+8	CCNU_你们好强啊我们都是面包手	F - Climb	GNU C++17	Accepted	1294 ms	59200 KB
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#define For(i,a,b) for(register int i=(a);i<=(b);++i)
#define Mst(a,b) memset(a,(b),sizeof(a))
using namespace std;
const int maxn = 1e5+20;
int a[maxn],p[maxn],n,cnt;//p离散化 
struct Edge{
	int to,Next;
}edge[maxn<<1];
int head[maxn],totEdge;//邻接表 
int First[maxn],sequence[maxn<<1],deep[maxn<<1];
int father[maxn];
bool vis[maxn]; //dfs 
int Min[maxn<<1][20];
int Log2[maxn<<1]={-1};
struct Node{
	Node * Lchild, * Rchild;
	int sum;
}node[maxn*20],*root[maxn*20];
Node * update(int,int,int,Node*); 
void build(); //建第一课空树(爷爷节点) 
void initG(); //初始化邻接表 
void addedge(int u,int v);
void dfs(int x,int fa,int deep,int&);
void getST(int n); 
int LCA(int x,int y);
int query(int,int,int,Node*,Node*,Node*,Node*);
int main()
{
	//freopen("in.txt","r",stdin);
	For(i,1,maxn*2-15) Log2[i] = Log2[i>>1]+1;
	int T,m;scanf("%d",&T);
	while(T--)
	{
		scanf("%d%d",&n,&m);
		For(i,1,n) scanf("%d",a+i), p[i] = a[i];
		sort(p+1,p+1+n);
		For(i,1,n) a[i] = lower_bound(p+1,p+1+n,a[i])-p;
		int u,v;
		initG();
		For(i,2,n)
		{
			scanf("%d%d",&u,&v);
			addedge(u,v);
			addedge(v,u);
		}	
		build(); //先建一棵空树
		Mst(vis,0); 
		int cntOfSequence = 0;
		dfs(1,0,1,cntOfSequence); //dfs生成树的同时,在父节点基础上建立新的线段树 
		int k,lca;
		getST(2*n-1); //线性预处理(nlogn) 
		while(m--)
		{
			scanf("%d%d%d",&u,&v,&k); 
			lca = LCA(u,v);
			int totNum = deep[First[u]]+deep[First[v]]-deep[First[lca]]-deep[First[father[lca]]];
			if(k>totNum) //询问的K大于这条路径上所有顶点的个数 
			{
				printf("-1\n");
				continue;
			}
			k = totNum - k+1;
			printf("%d\n",p[query(1,n,k,root[u],root[v],root[lca],root[father[lca]])]);
		}	
	} 
	
	return 0;	
}

void initG()
{
	Mst(head,-1);
	totEdge = 0;
}
void addedge(int u,int v)
{
	edge[totEdge].to = v;
	edge[totEdge].Next = head[u];
	head[u] = totEdge++;
}
void dfs(int x,int fa,int dep,int &cntOfSeq)
{
	father[x] = fa;
	vis[x] = true;
	root[x] = update(1,n,a[x],root[fa]);
	sequence[++cntOfSeq] = x;
	deep[cntOfSeq] = dep;
	First[x] = cntOfSeq;
	for(int i=head[x];i!=-1;i=edge[i].Next)
	{
		int to = edge[i].to;
		if(vis[to]) continue;
		vis[to] = true;
		dfs(to,x,dep+1,cntOfSeq);
		sequence[++cntOfSeq] = x;
		deep[cntOfSeq] = dep;
	}
}
void getST(int n)
{
	For(i,1,n) Min[i][0] = i;
	for(int j=1;(1<<j)<=n;++j)
	{
		for(int i=1;i+(1<<j)-1<=n;++i)
		{
			int a = Min[i][j-1];
			int b = Min[i+(1<<(j-1))][j-1];
			Min[i][j] = deep[a]>deep[b]?b:a;
		}
	}
} 
int LCA(int x,int y)
{
	x = First[x];
	y = First[y];
	if(x>y) swap(x,y);
	int j = Log2[y-x+1];
	int a = Min[x][j];
	int b = Min[y-(1<<j)+1][j];
	return deep[a]>deep[b]?sequence[b]:sequence[a];
}
Node * update(int left,int right,int v,Node * p)
{
	if(v<left||v>right) return p;
	Node * t = &node[cnt++];
	t->Lchild = p->Lchild;
	t->Rchild = p->Rchild;
	t->sum = p->sum + 1; 
	if(left==right) return t;
	int mid = (left+right)>>1;
	t -> Lchild = update(left,mid,v,p->Lchild);
	t -> Rchild = update(mid+1,right,v,p->Rchild);
	return t;	
}
void build()
{
	cnt = 0;
	root[0] = &node[cnt++];
	root[0]->Lchild = root[0]->Rchild = root[0];
	root[0]->sum = 0;
}
int query(int left,int right,int k,Node*ru,Node*rv,Node *rlca,Node*rfalca)
{
	if(left==right) return left;
	int tot = ru->Lchild->sum + rv->Lchild->sum 
	     - rlca->Lchild->sum - rfalca->Lchild->sum;
	int mid = (left+right)>>1;
	if(k<=tot) 
		return query(left,mid,k,ru->Lchild,rv->Lchild,rlca->Lchild,rfalca->Lchild);
	else 
		return query(mid+1,right,k-tot,ru->Rchild,rv->Rchild,rlca->Rchild,rfalca->Rchild);
}


队友们,我们一起加油叭!
好好训练,备战湘潭赛!
fighting!


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值