• 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:
    ",++ca);
    		scanf("%s",num);
    		LenNum = strlen(num)-1;
    		scanf("%d",&n);
    		For(ca,1,n)
    		{
    			scanf("%s",str);
    			if(ok())
    			{
    				printf("Maybe..
    ");
    			}
    			else
    			{
    				printf("How could that be possible?
    ");
    			}
    		}
    	} 
        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
    ",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
    ",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
    ");
    				continue;
    			}
    			k = totNum - k+1;
    			printf("%d
    ",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!


  • 相关阅读:
    P4097 [HEOI2013]Segment 李超线段树
    P3592 [POI2015]MYJ
    P3698 [CQOI2017]小Q的棋盘
    P4098 [HEOI2013]ALO 可持久化01Trie
    P2331 [SCOI2005]最大子矩阵
    P4099 [HEOI2013]SAO
    loj #6032. 「雅礼集训 2017 Day2」水箱 线段树优化DP转移
    CF765F Souvenirs 离线+线段树+主席树
    CF1097D Makoto and a Blackboard
    loj #6570. 毛毛虫计数
  • 原文地址:https://www.cnblogs.com/Apare-xzc/p/12243653.html
Copyright © 2020-2023  润新知