• 【比赛】百度之星2017 初赛Round A


    第一题

    题意:给定多组数据P,每次询问P进制下,有多少数字B满足条件:只要数位之和是B的倍数,该数字就是B的倍数。

    题解:此题是参考10进制下3和9倍数的特殊性质。

    对于10进制,ab=10*a+b=9*a+(a+b),所以9的约数都有此性质。

    对于P进制,ab=p*a+b=(p-1)a+(a+b),所以p-1的约数都有此性质。

    对于P,计算P-1的约数个数即为答案。

    ★第二题

    题意:给定L的关系(L<=10^5),关系表示为xi=xj或xi≠xj,将数据按顺序分为若干组(相邻在同一组),每组不满足所有条件,去掉最后一个条件后满足所有条件,求组数。

    题解:

    一种方法是每次倍增一组个数,对于组内跑bfs或者并查集,最后对组内不等关系判互恰,倍增结合二分。

    正解O(n log n)。

    相等关系具有传递性,可以用并查集在线维护。

    不等关系不具有传递性,用平衡树维护每个点的不等关系。

    对于相等关系,若在同一集合跳过,若在对方平衡树内则清空退出,否则合并双方集合。

    合并使用启发式合并,就是大的并入小的,并修改对应不等关系平衡树处的表示。

    对于不等关系,若在同一集合则清空退出,否则加入对方平衡树。

    清空退出:用到的点加入栈,清空时只清栈内平衡树和栈内父亲,保证复杂度。(vis时间戳也可以优化常数)

    记得开双倍数组。

    #include<cstdio>
    #include<cstring>
    #include<set>
    #include<stack>
    #include<algorithm>
    using namespace std;
    const int maxn=200010;
    
    int ans,anss[maxn],pre,n,fa[maxn];
    stack<int>s;
    set<int>q[maxn];
    set<int>::iterator it;
    
    void getans(int x){
        anss[++ans]=x-pre;pre=x;
        while(!s.empty()){
            q[s.top()].clear();
            fa[s.top()]=s.top();
            s.pop();
        }
    }
    int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
    
    int main(){
        scanf("%d",&n);
        int u,v,w;
        pre=0;
        for(int i=1;i<=n;i++)fa[i]=i;//初始化 
        for(int i=1;i<=n;i++){
            scanf("%d%d%d",&u,&v,&w);
            s.push(u);s.push(v);
            u=find(u);v=find(v);
            if(w==1){
                if(u==v)continue;
                if(q[u].find(v)!=q[u].end())getans(i);
                else{
                    if(q[u].size()>q[v].size())swap(u,v);
                    for(it=q[u].begin();it!=q[u].end();it++){
                        q[*it].erase(u);
                        q[*it].insert(v);
                        q[v].insert(*it);
                    }
                    fa[u]=v;
                }
            }else{
                if(u==v)getans(i);
                else{
                    q[u].insert(v);
                    q[v].insert(u);
                }
            }
        }
        printf("%d
    ",ans);
        for(int i=1;i<=ans;i++)printf("%d
    ",anss[i]);
        return 0;
    }
    View Code

    另一种解法:如果只有一组,显然全局二分后找最长长度。

    因为答案就有明显的递进性质,所以考虑使用倍增来扩展,失败后在使用区间二分,保证复杂度。

    复杂度……是啥?代码未AC。

    #include<cstdio>
    #include<cstring>
    #include<stack>
    #include<algorithm>
    using namespace std;
    const int maxn=200010;
    
    int ans,anss[maxn],pre,n,fa[maxn];
    int a[maxn],b[maxn],c[maxn];
    int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
    
    bool found(int l,int r){
        bool ok=1;
        for(int i=l;i<=r;i++)if(c[i]&&find(a[i])!=find(b[i]))fa[fa[a[i]]]=fa[b[i]];
        for(int i=l;i<=r;i++)if((!c[i])&&find(a[i])==find(b[i])){ok=0;break;}
        for(int i=l;i<=r;i++)fa[i]=i;
        return ok;
    }
    int half(int x,int l,int r){
        int mid;
        while(l<r){
            mid=(l+r)>>1;
            if(found(x,mid))l=mid+1;
            else r=mid;
        }
        return l;
    }
    int main(){
        scanf("%d",&n);
        int now=1;
        for(int i=1;i<=n;i++)fa[i]=i;//初始化
        for(int i=1;i<=n;i++)scanf("%d%d%d",&a[i],&b[i],&c[i]);
        while(now<=n){
            int mx=0;
            while(now+(1<<mx)<=n&&found(now,now+(1<<mx)))mx++;
            if(mx==0){ans++;now++;anss[ans]=now;}
            else{
                now=half(now,now+(1<<(mx-1)),min(n,now+(1<<mx)));
                ans++;anss[ans]=now;
                now++;
            }
        }
        printf("%d
    ",ans);
        for(int i=1;i<=ans;i++)printf("%d
    ",anss[i]-anss[i-1]);
        return 0;
    }
    Wrong Answer

    ★第三题

    题意:给定n个点的树,m条路径(u到v)构成序列,q次询问序列L到R路径的交集。

    题解:套路化地化树上询问为链上询问,处理一堆细节。

    http://paste.ubuntu.com/25312404/

    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <set>
    
    #define rep(i, l, r) for(int i=l; i<=r; i++)
    #define dow(i, l, r) for(int i=l; i>=r; i--)
    #define clr(x, c) memset(x, c, sizeof(x))
    #define travel(x) for(edge *p=fir[x]; p; p=p->n)
    #define all(x) (x).begin,(x).end
    #define pb push_back
    #define fi first
    #define se second
    #define l(x) Left[x]
    #define r(x) Right[x]
    #define lowbit(x) (x&-x)
    
    using namespace std;
    
    typedef long long ll;
    typedef pair<int,int> Pii;
    typedef long double ld;
    typedef unsigned long long ull;
    
    inline int read()
    {
        int x=0; bool f=0; char ch=getchar();
        while (ch<'0' || '9'<ch) f|=ch=='-', ch=getchar();
        while ('0'<=ch && ch<='9') x=x*10+ch-'0', ch=getchar();
        return f?-x:x;
    }
    
    #define maxn 500009
    #define maxc 1000009
    
    int n, m;
    
    struct edge{int y,z; edge *n;} e[maxn*2], *fir[maxn], *pt=e;
    void AddE(int x, int y, int z)
    {
        pt->y=y, pt->z=z, pt->n=fir[x], fir[x]=pt++;
        pt->y=x, pt->z=z, pt->n=fir[y], fir[y]=pt++;
    }
    
    
    int h[21][maxn], dep[maxn]; ll d[maxn];
    
    inline int lca(int a, int b)
    {
        if (dep[a]<dep[b]) swap(a,b);
        for(int i=0, tmp=dep[a]-dep[b]; tmp; tmp>>=1,i++) if (tmp&1) a=h[i][a];
        if (a==b) return a;
        dow(i,20,0) if (h[i][a] && h[i][a]!=h[i][b]) a=h[i][a], b=h[i][b];
        return h[0][a];
    }
    
    
    
    int cn, rt, Left[maxc], Right[maxc]; Pii g[maxc];
    inline Pii Union(Pii p0, Pii p1)
    {
        if (p0==Pii(1,1) || p1==Pii(1,1)) return Pii(1,1);
        
        int x1=p0.fi, y1=p0.se;
        int x2=p1.fi, y2=p1.se, a, b, c, d;
        if ((a=lca(x1,y1))==(b=lca(x2,y2)))
        {
            if (lca(x1,x2)==lca(x1,y1)) swap(x2,y2);
            Pii tmp=Pii(lca(x1,x2),lca(y1,y2));
            if (tmp.se==tmp.fi) return Pii(1,1); else return tmp;
        }
        else
        {
            if (dep[a]<dep[b]) swap(x1,x2), swap(y1,y2), swap(a,b);
            c=lca(x1,x2), d=lca(y1,x2); if ((c==a) || (d==a)) return Pii(c,d);
            c=lca(x1,y2), d=lca(y1,y2); if ((c==a) || (d==a)) return Pii(c,d);
            else return Pii(1,1);
        }
        return Pii(1,1);
    }
    void Build(int l, int r, int &t)
    {
        t=++cn; if (l==r) {g[t]=Pii(read(),read()); return;}
        int mid=(l+r)>>1;
        Build(l,mid,l(t)); Build(mid+1,r,r(t));
        g[t]=Union(g[l(t)],g[r(t)]);
    }
    
    
    int L, R; Pii G;
    void Que(int l, int r, int &t)
    {
        if (L<=l && r<=R)
        {
            if (G.fi==0) G=g[t]; else G=Union(G,g[t]);
            return;
        }
        int mid=(l+r)>>1;
        if (L<=mid) Que(l,mid,l(t)); 
        if (mid<R) Que(mid+1,r,r(t));
    }
    
    
    
    int q[maxn], tot;
    int main()
    {
        n=read();
        rep(i, 1, n-1) {int x=read(), y=read(), z=read(); AddE(x,y,z);}
        q[tot=1]=1; while (tot)
        {
            int x=q[tot--];
            for(int i=1;h[i-1][h[i-1][x]];i++) h[i][x]=h[i-1][h[i-1][x]];
            travel(x) if (p->y!=h[0][x]) q[++tot]=p->y, h[0][p->y]=x, d[p->y]=d[x]+p->z, dep[p->y]=dep[x]+1;
        }
        Build(1,m=read(),rt);
        int Q=read(); while (Q--)
        {
            L=read(), R=read(); G=Pii(0,0);
            Que(1,m,rt);
            printf("%I64d
    ", d[G.fi]+d[G.se]-d[lca(G.fi,G.se)]*2);
        }
        return 0;
    }
    嗷嗷待补

    第四题

    第五题

    题意:多组数据,给定年月日,求下一次同月同日为同星期几的年份。

    题解:365%7=1,过一年星期加一天。

    对于2.29前的日子,闰年在本年多+1。对于2.29后的日子,闰年在本年多+1。

    对于2.29,四年四年跳特殊处理,还要处理跳到的年份是否闰年。

    第六题

    题意:给定一个n*m的01矩阵。

    图像0的定义:存在1字符且1字符只能是由一个连通块组成,存在且仅存在一个由0字符组成的连通块完全被1所包围。

    图像1的定义:存在1字符且1字符只能是由一个连通块组成,不存在任何0字符组成的连通块被1所完全包围。

    连通的含义是,只要连续两个方块有公共边,就看做是连通。

    完全包围的意思是,该连通块不与边界相接触。

    题解:

    要用巧妙的方法判断,否则会极其复杂。

    在外圈加0后,从外圈到内圈消除,转化为:

    图像0:一圈0连通块,一圈1联通块,一圈0联通块。

    图像1:一圈0连通块,一圈1联通块。

    注意每圈只能有1个联通块。

  • 相关阅读:
    HTML基础
    JavaScript基础
    J2EE技术(六)——JSP
    2011.2—至今年度总结
    J2EE技术(二)——JDBC
    DRP项目总结(一)——项目简介
    CSS基础
    J2EE技术(五)——EJB
    J2EE技术(三)——JMS
    J2EE技术(四)——JavaMail
  • 原文地址:https://www.cnblogs.com/onioncyc/p/7351318.html
Copyright © 2020-2023  润新知