【博客】WHU校赛2019(网络赛) 解题报告

<font color="purple">WHU校赛2019(网络赛) 解题报告</font>

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);
}

<font color="orange" size=5 face="华文楷体">队友们,我们一起加油叭!</font>
<font color="purple" size=6 face="华文行楷">好好训练,备战湘潭赛!</font>
<font color="green" size=5 face="consola">fighting!</font>


全部评论
我的CSDN博客链接: https://blog.csdn.net/qq_40531479/article/details/89117117
点赞 回复 分享
发布于 2019-04-10 07:18

相关推荐

头像
11-06 10:58
已编辑
门头沟学院 嵌入式工程师
双非25想找富婆不想打工:哦,这该死的伦敦腔,我敢打赌,你简直是个天才,如果我有offer的话,我一定用offer狠狠的打在你的脸上
点赞 评论 收藏
分享
2 收藏 评论
分享
牛客网
牛客企业服务