• 「10.10」神炎皇(欧拉函数)·降雷皇(线段树,DP)·幻魔皇


    A. 神炎皇


    很好的一道题,可能第一次在考场上遇到欧拉函数

    题意:对于一个整数对 $(a,b)$,若满足 $a imes bleq n$且$a+b$是$a imes b$的因子,

    则称为神奇的数对。问这样的数对共有个?

    首先式子同时除一个$gcd(a,b)$,那么设$d=gcd(a,b)$,则$a=A/d,b=B/d$,

     所以因为$a$,$b$,中已经将因子全部提出,所以$a imes b$与$a+b$是互质的

    然后设$k$为$d/(a+b)$,显然$k imes (a+b) imes (a+b)leq n$

    因此$kleq n/(x imes x)$

    同时对于$a+b$我们只需枚举到$sqrt{n} $即可

    那么考虑范围,对于每个枚举的$i=a+b$,那么显然$k$的取值是$n/(i*i)$,

    然后对于$i$我们可以求出$varphi {i}$,

    因为$a+b=i$,所以对于每个与$i$互质的数$x$可得$gcd(i,x)==1$,即

    $gcd(i-x,x)==1$。

     时间复杂度$O(sqrt{n} )$.

    #include<bits/stdc++.h>
    #define MAXN 11000000
    #define int long long
    using namespace std;
    int phi[MAXN],vis[MAXN],pri[MAXN];
    int n;
    int read(){
        int x=0;char c=getchar();
        while(c<'0'||c>'9')c=getchar();
        while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
        return x;
    }
    void shai(){
        for(int i=2;i<=sqrt(n);++i){
            if(!vis[i]){vis[i]=1;pri[++pri[0]]=i;phi[i]=i-1;}
            for(int j=1;j<=pri[0],i*pri[j]<=sqrt(n);++j){
                if(i%pri[j]==0){
                    phi[i*pri[j]]=phi[i]*pri[j];
                    vis[i*pri[j]]=1;
                    break;
                }
                phi[i*pri[j]]=phi[i]*(pri[j]-1);
                vis[i*pri[j]]=1;
            }
        }
    }
    int ans=0;
    signed main(){
        n=read();
        shai();
        for(int i=1;i*i<=n;++i){
            ans=ans+(n/(i*i))*phi[i];    
            //printf("i=%lld ans=%lld %lld
    ",i,ans,phi[i]);
        }
        printf("%lld
    ",ans);
    }
    View Code

    B. 降雷皇


     线段树优化DP。也可以CDQ分治。

    C. 幻魔皇


    很好题递推题。

    首先每层的黑色节点数,白色节点数一定是斐波那契数列。

    证明的话:首先每层节点数=每层黑色节点数+每层白色节点数=上层节点数+上上层节点数,是斐波那契数列

    黑色节点数=上层节点数,白色节点数=上上层节点数,所以都是斐波那契数列。

    统计几个数组$fw_{i}$表示以白点为根的子树深度为$i$时的白点个数(深度从零开始)

    $fb_{i}$表示以黑点为根的子树深度为$i$时的黑点个数,

    然后统计出$sumw_{i}$,$sumb_{i}$即前缀和

    然后我们发现对于以某一黑点或白点为根时只要深度一样其最终的形状一定相同

    那么我们就可以分类讨论,两个白点组成路径:

    $1.$以白点为$lca$时:

    $ans_{i}=fw_{i} imes sumw_{n-i-1}$

    即我们假设一点为根节点,那么我们考虑有多少子树符合情况,显然是个前缀和

    $2.$以黑点为$lca$时

    $ans_{i}=sum_{k}^{i-1} fw_{k-1} imes fb_{i-k-1} imes sumb_{n-1-max(k,i-k)}$

    我们以黑点为$lca$那么枚举他的两个子树的白点深度,再统计出他的子树个数。

    #include<bits/stdc++.h>
    #define MAXN 11000000
    #define int long long
    using namespace std;
    int n;
    const int mod=123456789;
    int read(){
        int x=0;char c=getchar();
        while(c<'0'||c>'9')c=getchar();
        while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
        return x;
    }
    int f_w[MAXN],f_b[MAXN],sum_w[MAXN],sum_b[MAXN];
    int ans[MAXN];
    signed main(){
        n=read();
        f_w[0]=1;f_w[1]=0;f_w[2]=1;f_w[3]=1;
        for(int i=4;i<=n;++i){
            f_w[i]=(f_w[i-1]+f_w[i-2])%mod;
        }
        f_b[0]=0;f_b[1]=1;
        for(int i=2;i<=n;++i){
            f_b[i]=(f_b[i-1]+f_b[i-2])%mod;
        }
        sum_w[0]=f_w[0];sum_b[0]=f_b[0];
        for(int i=1;i<=n;++i){
            sum_w[i]=(sum_w[i-1]+f_w[i])%mod;
            sum_b[i]=(sum_b[i-1]+f_b[i])%mod;
        }
        for(int i=1;i<=n*2;++i){
            ans[i]=(ans[i]+f_w[i]*sum_w[n-i-1])%mod;        
            //printf("ans[%lld]=%lld
    ",i,ans[i]);
        }
        for(int i=3;i<=n*2;++i){
            for(int k=1;k<=i-1;++k){
                ans[i]=(ans[i]+f_w[k-1]%mod*f_b[(i-k)-1]%mod*sum_b[n-1-max(k,i-k)]%mod)%mod;
                //printf("ans[%lld]=%lld k=%lld
    ",i,ans[i],k);
            }
        }
        for(int i=1;i<=2*n;++i){
            printf("%lld ",ans[i]);
        }
    }
    View Code
  • 相关阅读:
    angularJS处理table中checkbox的选中状态
    大公司常见表格样式
    github:当你想要使用VSCODE开心提交代码时,出现Git:git@github.com:Permission denied(publickey)解决方案
    angularjs 使用angular-sortable-view实现拖拽效果(包括拖动完成后的方法使用)
    sortable结合angularjs实现拖动排序
    promise的一个简单易懂实例
    angular-ui-select (系列二)远程搜索,页面方框显示的值跟传给后台的值不一样解决方案
    leetcode刷题笔记二十九 两数相除
    scala学习 包和引入
    leetcode刷题笔记二十六 、 二十七、 二十八
  • 原文地址:https://www.cnblogs.com/Wwb123/p/11647795.html
Copyright © 2020-2023  润新知