• 【日常摸鱼】牛客挑战赛46(未完)


    【日常摸鱼】牛客挑战赛46

    前言

    日渐消沉,随便做几题,假装我还在练acm。

    A 奇怪的计算器

    水题略了

    B 最小的指数

    链接

    https://ac.nowcoder.com/acm/contest/9510/B

    题意

    询问正整数x的质因数的指数的最小值。数据组数1e5,n的范围1e18。

    题解

    这个操作还挺有趣的。。
    先筛掉4000以内的所有质数,然后剩下的质数的指数不会超过4。
    然后如果最小指数是4,那肯定能开4次方,(其他情况会有更小的指数)
    如果最小指数是3,那肯定能开3次方,(其他情况会有更小的指数)
    如果最小指数是2,那就要求能开2次方,但不能开4次方。
    其余的就是1次的了。

    (Code)

    #include <bits/stdc++.h>
    #define LL long long
    #define ull unsigned long long
    #define LD long double
    using namespace std;
    const int N=3e5+10;
    const LL INF=1e18;
    LL read(){
        LL x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    void print(LL x){
        if(x>9) print(x/10);
        putchar(x%10+'0');
    }
    int cnt=0;
    bool vis[4050];
    int p[4050];
    LL qpow(LL x,int y){
        LL res=1;
        for(int i=1;i<=y;++i) {
            if(res<=INF/x) res=res*x;
            else res=INF;
        }
        return res;
    }
    LL sqr(LL x,int y){
        LL l=1,r=1e9,mid;
        while(l!=r){
            mid=(l+r+1)>>1;
            if(qpow(mid,y)<=x) l=mid;
            else r=mid-1;
        }
        return l;
    }
    int main(){
        for(int i=2;i<=4000;++i){
            if(!vis[i]){
                p[++cnt]=i;
                for(int j=i+i;j<=4000;j+=i) vis[j]=1;
            }
        }
        int T=read();LL n,x,y,mn;
        while(T--){
            n=read();mn=100;
            if(n==1){
                puts("0");
                continue;
            }
            //cout<<n<<endl;
            for(int i=1;i<=cnt;++i){
                x=0;
                while(n%p[i]==0){
                    n=n/p[i];
                    ++x;
                }
                if(x)mn=min(mn,x);
            }
            //cout<<n<<endl;
            if(n>1){
                x=sqr(n,4);
                if(x*x*x*x==n) mn=min(mn,(LL)4);
                else{
                    x=sqr(n,3);
                    if(x*x*x==n) mn=min(mn,(LL)3);
                    else{
                        x=sqr(n,2);
                        if(x*x==n) mn=min(mn,(LL)2);
                        else mn=min(mn,(LL)1);
                    }
                }
            }
            print(mn);puts("");
        }
        return 0;
    }
    

    C 排列

    链接

    https://ac.nowcoder.com/acm/contest/9510/C

    题意

    求长度为n,并且恰好有k个超级逆序对的排列的个数。n,k不超过500。超级逆序对就是两个数的数值之差至少为2的逆序对。

    题解

    就是前缀和优化一下DP就行了。

    (Code)

    #include <bits/stdc++.h>
    #define LL long long
    #define ull unsigned long long
    #define LD long double
    using namespace std;
    const int N=3e5+10;
    const LL P=998244353;
    int read(){
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    void print(LL x){
        if(x>9) print(x/10);
        putchar(x%10+'0');
    }
    void add(int &x,int y){
        x+=y;if(x>=P)x-=P;
    }
    LL qpow(LL x,LL y){
        LL re=1;
        while(y){
            if(y&1) re=re*x%P;
            x=x*x%P;y>>=1;
        }
        return re;
    }
    int n,K;
    int f[510][510][510+510];
    
    int main(){
        scanf("%d%d",&n,&K);
        f[1][1][0]=1;
        for(int i=1;i<=n;++i){
            for(int j=i;j>=1;--j){
                for(int k=0;k<=K;++k){
                    if(k>0) add(f[i][j][k],f[i][j+1][k-1]);
                    if(f[i][j][k]){
                        add(f[i+1][i+1][k],f[i][j][k]);
                        add(f[i+1][j][k+(i-j)+1],P-f[i][j][k]);
                        add(f[i+1][j][k+(i-j)],f[i][j][k]);
                    }
                }
            }
        }
        int ans=0;
        for(int i=1;i<=n;++i) add(ans,f[n][i][K]);
        printf("%lld
    ",qpow((LL)ans,P-2));
        return 0;
    }
    

    D 数列

    链接

    https://ac.nowcoder.com/acm/contest/9510/D

    题意

    给一个长度为n的数列,求区间内每个数出现次数恰好为k的倍数的区间数。n,ai,k不超过1e6.

    题解

    给每个位置赋一个随机值,并且使任意连续的k个一样的数的随机值之和为0.
    然后询问相当于有多少区间的赋值之和为0,这个就很容易做了。

    (Code)

    #include <bits/stdc++.h>
    #define LL long long
    #define ull unsigned long long
    #define LD long double
    using namespace std;
    const int N=1e6+10;
    const LL P=998244353;
    const LL INF=1e18;
    int read(){
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    void print(LL x){
        if(x>9) print(x/10);
        putchar(x%10+'0');
    }
    unordered_map<LL,LL> mp;
    int n,K;
    int a[N],c[N];
    vector<LL> ve[N];
    LL sum[N],b[N];
    int main(){
        srand(time(0));
        LL x,ans=0;
        scanf("%d%d",&n,&K);mp[0]=1;
        for(int i=1;i<=n;++i){
            scanf("%d",&a[i]);
            ++c[a[i]];
            if(c[a[i]]<K){
                x=rand()*rand()%INF*rand()%INF;
                sum[a[i]]+=x;
                ve[a[i]].push_back(x);
            }
            else if(c[a[i]]==K){
                sum[a[i]]=-sum[a[i]];
                ve[a[i]].push_back(sum[a[i]]);
            }
            b[i]=ve[a[i]][(c[a[i]]+K-1)%K];
            b[i]+=b[i-1];
            ans+=mp[b[i]];
            mp[b[i]]++;
        }
        printf("%lld
    ",ans);
        return 0;
    }
    

    E 反演

    链接

    https://ac.nowcoder.com/acm/contest/9510/E

    题解

    题目要求的式子 (sum_{i=1}^{n}sum_{j|m!}sigma_{0}(ij))
    两数乘积的约数个数是可以转化成公约数有关的式子的。
    (sum_{i=1}^{n}sum_{j|m!}sigma_{0}(ij)) (=) (sum_{i=1}^{n}sum_{j|m!}sum_{x|i}sum_{y|j}[(x,y)=1])
    然后就是喜闻乐见的莫比乌斯反演推式子的套路。。这里直接给出推完之后的式子
    (sum_{t|m!}mu(t)sum_{y|frac{m!}{t}}sigma_{0}(frac{m}{ty})sum_{i=1}^{lfloor frac{n}{t} floor}lfloor frac{n}{it} floor)
    由于m不超过100,也就是说质数最多只有25个,有用的莫比乌斯函数也只有(2^{25})个,于是枚举莫比乌斯函数不为0的项加起来就可以了。

    (Code)

    #include <bits/stdc++.h>
    #define LL long long
    using namespace std;
    const int N=3e5+10;
    const LL P=998244353;
    int read(){
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    void print(LL x){
        if(x>9) print(x/10);
        putchar(x%10+'0');
    }
    LL n,nn;
    LL inv[100005],c[110];
    int m,cnt;
    int vis[110];
    int p[110];
    LL mp[1000000],MP[1000000];
    LL F(LL x){
        if(x<=nn&&mp[x]) return mp[x];
        if(x>nn&&MP[(n/x)]) return MP[(n/x)];
        LL res=0,v;
        for(LL i=1,j;i<=x;i=j+1){
            v=x/i;
            j=x/v;
            res+=v*(j-i+1);
        }
        res=res%P;
        if(x<=nn) mp[x]=res;
        if(x>nn) MP[(n/x)]=res;
        return res;
    }
    LL ans;
    void sol(int id,LL t,LL mu,LL sum){
        if(t>n) return;
        if(id>cnt){
            ans+=mu*F(n/t)%P*sum%P;
            return; 
        }
        sol(id+1,t,mu,sum);
        sol(id+1,t*(LL)p[id],P-mu,sum*inv[c[id]+2]%P*c[id]%P);
    }
    int main(){
        inv[0]=inv[1]=1;
        for(LL i=2;i<=100000;++i) inv[i]=(P-P/i)*inv[P%i]%P;
        cin>>n>>m;nn=sqrt(n);cnt=0;ans=0;
        for(int i=2;i<=m;++i){
            if(!vis[i]){
                p[++cnt]=i;
                for(int j=i+i;j<=m;j+=i){
                    vis[j]=1;
                }
            }
        }
        int x;LL tot=1;
        for(int i=1;i<=cnt;++i){
            c[i]=0;x=m;
            while(x>0){
                x=x/p[i];
                c[i]+=x;
            }
            tot=tot*(c[i]+2)%P*(c[i]+1)%P*inv[2]%P;
        }
        sol(1,1LL,1LL,tot);
        ans=(ans%P+P)%P;
        printf("%lld
    ",ans);
        return 0;
    }
    

    F 柠檬树

    链接

    https://ac.nowcoder.com/acm/contest/9510/F

    题解

    我也还不会,这个LCT太神了QAQ

  • 相关阅读:
    小数的进制转换
    水题 O
    水题 J
    水题T,二进制转16进制
    水题B
    水题C
    HDU 2042
    HDU 2041
    Index For SQL Server
    Learning Note For Angular
  • 原文地址:https://www.cnblogs.com/Yuigahama/p/14197564.html
Copyright © 2020-2023  润新知