zoukankan      html  css  js  c++  java
  • HGOI 20190708 题解

    Problem A 拿出勇气吧

    幸运数字每一位是$4$或者$7$,现在给出一个数字每位数位上数的和为n,求出最小的幸运数n

    对于100%的数据,$nleq 10^6$

    Sol : 显然本题要求数的长度尽可能短,于是显然是先放$7$放$4$并且$7$放在较低位。

    这就等价于求不定方程$4x + 7y = n $的最小整数解x,然后只要延续输出x个4,y个7即可。

    只需要做一次exgcd就可以求出。

    复杂度应该是答案的长度 $O(length)$

    # include <bits/stdc++.h>
    # define int long long
    using namespace std;
    struct node {
        int x,y; bool flag;
    };
    int exgcd(int a,int b,int &x,int &y)
    {
        if (b==0) {
            x=1;y=0;
            return a;
        }
        int g=exgcd(b,a%b,x,y);
        int t=x;x=y;y=t-a/b*x;
        return g;
    }
    node getmin(int a,int b,int c) 
    {
        int x,y; int g=exgcd(a,b,x,y);
        if (c%g!=0) return (node){-1,-1,false};
        int k=c/g,ga=a/g,gb=b/g;
        x=(x*k%gb+gb)%gb;
        y=(c-a*x)/b;
        return (node){x,y,true};
    }
    signed main()
    {
        int n;scanf("%d",&n);
        node t=getmin(4,7,n);
        for (int i=1;i<=t.x;i++) printf("4");
        for (int i=1;i<=t.y;i++) printf("7"); 
        return 0;
    }
    Courage.cpp

    Problem B 生死之对决

    幸运数字每一位是$4$或者$7$,给出$ p in [pl,pr] in Z,v in [vl,vr] in Z $ 且$p,v$ 在所属区间等概率出现。

    求出区间$[min{v,p} , max {v,p}]$包含幸运数字恰好是$k$个的概率。

    对于100%的数据$1 leq ql leq qr leq 10^9,1 leq vl leq vr leq 10^9,1 leq k leq 10^3 $

    Sol :首先在$[1,10^9]$的幸运数字是$2^1 + 2^2 + ... + 2^9 = 1022$个,所以我们可以基于枚举每一个幸运数字对答案造成的贡献(用乘法原理)来进行计数。

    设排序后的幸运数字为$p_i (1leq i leq 1022)$ 那么我们枚举第$p_i $到$p_{i+k-1}$这$k$个幸运数字在$[min{v,p} , max{v,p}]$区间内。

    所以有$min{p,v} in [p_{i-1} +1 , p_i] ,max{p,v} in [p_{i+k-1},p_{i+k}-1]$ 

    为了拆掉$min,max$所以我们要讨论$p,v$的大小关系。

    当$p leq v$ 时显然有 $p in  [p_{i-1} +1 , p_i]  , v in  [p_{i+k-1},p_{i+k}-1] $ 

    当$p geq v$ 时显然有 $v in [p_{i-1} +1 , p_i] , p in [p_{i+k-1},p_{i+k}-1]  $

    注意到上述我们在$p = v $的时候可能会重复计算,而且当且仅当$ k = 1$的时候出现,所以需要特判。

    # pragma GCC optimize(3) 
    # include <bits/stdc++.h>
    # define int long long
    using namespace std;
    const int N=2e3+100;
    int p[N];
    int n;
    void getlucky(int num,int lim)
    {
        if (num>lim) return;
        if (num!=0) p[++n]=num;
        getlucky(num*10+4,lim);
        getlucky(num*10+7,lim);
    }
    signed main()
    {
        getlucky(0,2e9); int pl,pr,vl,vr,k; 
        scanf("%lld%lld%lld%lld%lld",&pl,&pr,&vl,&vr,&k);
        sort(p+1,p+1+n);
        p[n+1]=2e9+10; int ans=0;
        for (int i=1;i<=n;i++) {
            if (min(p[i],pr)-max(p[i-1]+1,pl)+1>=0&&min(p[i+k]-1,vr)-max(p[i+k-1],vl)+1>=0) {
                ans+=(min(p[i],pr)-max(p[i-1]+1,pl)+1)*(min(p[i+k]-1,vr)-max(p[i+k-1],vl)+1);
            }
            if (min(p[i+k]-1,pr)-max(p[i+k-1],pl)+1>=0&&min(p[i],vr)-max(p[i-1]+1,vl)+1>=0) {
                ans+=(min(p[i+k]-1,pr)-max(p[i+k-1],pl)+1)*(min(p[i],vr)-max(p[i-1]+1,vl)+1);
            }
        }
        if (k==1) {
            for (int i=1;i<=n;i++)
             if (p[i]>=vl&&p[i]<=vr&&p[i]>=pl&&p[i]<=pr) ans--;
        } 
        printf("%.12lf
    ",(double)ans/(double)(vr-vl+1)/(double)(pr-pl+1));
        return 0;
    }
    Match.cpp

    Problem C 最后的结局

    一棵树上的点和父亲之间可能是存在魔法边和普通边,定义合法三元组$(i,j,k)$表示从$i$出发到$j$路径上和$i$出发到$k$路径上都至少存在一条魔法边。

    注意到不同的$(i,j,k)$都算不同的合法三元组。计算这棵树中合法三元组的数目。

    对于100%的数据 $ 1 leq n leq 10^5 $

    Sol : 直接树形DP即可,设$f_u$ 表示节点 $u$ 跑到所有节点的路径中含有魔法边的节点个数。

           第一次跑dfs从儿子更新到父亲,转移方程是 $f_{u}= sumlimits_{v in u_{son}} left{egin{matrix} size_{v}&(u,v) is magic edge  \  f_{v}&  (u,v) isn't magic edge  end{matrix} ight.$

          第二次跑dfs从父亲更新到儿子,转移方程是$f_v = left{egin{matrix} f_u & (u,v)  isn't magic edge\  n-size_v & (u,v) is magic edge end{matrix} ight.$ 

      复杂度$O(n)$

    # pragma GCC optimize(3) 
    # include<bits/stdc++.h>
    # define int long long
    using namespace std;
    const int N=1e5+10;
    struct rec{
        int pre,to,w;
    }a[N<<1];
    int f[N],tot,head[N],size[N],n;
    bool check(int x) {
        while (x) {
            if (!(x%10==4||x%10==7)) return false;
            x/=10;
        }
        return true;
    }
    void adde(int u,int v,int w)
    {
        a[++tot].pre=head[u];
        a[tot].to=v;
        a[tot].w=w;
        head[u]=tot;
    }
    void dfs1(int u,int fa) 
    {
        size[u]=1; f[u]=0;
        for (int i=head[u];i;i=a[i].pre) {
            int v=a[i].to; if (v==fa) continue;
            dfs1(v,u);  size[u]+=size[v]; 
            if (a[i].w==1) f[u]+=size[v];
            else f[u]+=f[v];
        }
    }
    void dfs2(int u,int fa) 
    {   
        for (int i=head[u];i;i=a[i].pre) {
            int v=a[i].to; if (v==fa) continue;
            if (a[i].w==1) f[v]+=n-size[v];
            else f[v]=f[u]; 
            dfs2(v,u);
        }
    } 
    signed main()
    {
    //  freopen("ending.in","r",stdin);
    //  freopen("ending.out","w",stdout);
        scanf("%lld",&n);
        for (int i=1;i<n;i++) {
            int u,v,w; scanf("%lld%lld%lld",&u,&v,&w);
            if (check(w)) adde(u,v,1),adde(v,u,1);
            else adde(u,v,0),adde(v,u,0);
        } 
        dfs1(1,0); dfs2(1,0);
        int ans=0;
        for (int i=1;i<=n;i++) ans+=(long long)f[i]*(f[i]-1);
        printf("%lld
    ",ans); 
        return 0;
     }
    Ending.cpp

     

  • 相关阅读:
    Python标准模块--logging
    Spark中决策树源码分析
    常见的相似或相异程度计算方法
    mpi4py实践
    集成学习
    决策树
    git使用
    Ubuntu 14.04 64bit 安装tensorflow(GPU版本)
    KNN算法
    一致性哈希算法原理及其在分布式系统中的应用
  • 原文地址:https://www.cnblogs.com/ljc20020730/p/11151260.html
Copyright © 2011-2022 走看看