• AtCoder Regular Contest 116 总结


    A

    判断奇偶因子谁多谁少

    容易发现如果质因数分解,有 n 个 2 和 m 个非 2 质因子

    则奇数因子有 $2^m$ 个 ,偶数因子有 $2^{n+m-1}$ 个(没有 2 时没有)

    可知当 n=0 时奇数多, n=1 时一样, n=2 时偶数多

    #include <iostream>
    #include <cstdio>
    using namespace std;
    typedef long long ll;
    int t;
    ll n;
    
    int main() {
        for (scanf("%d",&t);t;t--) {
            scanf("%lld",&n);
            if (n%2!=0) {printf("Odd\n");continue;}
            n/=2;
            if (n%2!=0) {printf("Same\n");continue;}
            else printf("Even\n");
        }
    }
    View Code

    B

    求对于一个序列 A ,它的子序列 B 的 $\sum_B max(B)*min(B)$

    将 A 排序,枚举左右端点为 l,r ,则当前答案为 $a[l]*a[r]*2^{r-l-1} (r>l)$ 再加上 $a[l]*a[r] (r=l)$

    考虑用后缀和维护 $a[r]*2^{r-1}$ 则枚举左端点 l 时答案为 $a[l]*s[r]*2^{-l} (r>l)$ 再加上 $a[l]*a[r] (r=l)$

    时间复杂度 O(n)

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    using namespace std;
    typedef long long ll;
    const ll P=998244353;
    const int N=2e5+10;
    int n;
    ll a[N],_2[N],suf[N],ans;
    
    ll Pow(ll x,ll y) {ll ans=1;for (;y;y>>=1,x=x*x%P) if (y&1) ans=ans*x%P;return ans;}
    
    int main() {
        scanf("%d",&n);
        _2[0]=1;for (int i=1;i<=n;i++) scanf("%lld",&a[i]),_2[i]=(_2[i-1]<<1)%P;
        sort(a+1,a+n+1);
        for (int i=n;i;i--)    suf[i]=(suf[i+1]+a[i]*_2[i-1]%P)%P;
        for (int i=1;i<=n;i++)
            (ans+=a[i]*suf[i+1]%P*Pow(_2[i],P-2)%P+a[i]*a[i]%P)%=P;
        printf("%lld\n",ans);
    }
    View Code

    C

    在一个序列中不同的数至多有 $log_2m$ 个

    则设 f[i][j] 表示第 i 个不同的数是 j , 从上一个 j 的因子里转移过来,复杂度是调和级数 O(nlnn)

    最后枚举有 i 个不同的数,在 n-1 个空隙里插 i-1 个板即可

    #include <iostream>
    #include <cstdio>
    #include <cmath>
    using namespace std;
    typedef long long ll;
    const ll P=998244353;
    const int N=2e5+10;
    int n,m,lg;
    ll fact[N],inv[N],f[21][N],ans;
    
    ll Pow(ll x,ll y) {ll ans=1;for (;y;y>>=1,x=x*x%P) if (y&1) ans=ans*x%P;return ans;}
    
    ll C(int n,int m) {return fact[n]*inv[n-m]%P*inv[m]%P;}
    
    int main() {
        scanf("%d%d",&n,&m);lg=log2(m);
        fact[0]=1;for (int i=1;i<N;i++) fact[i]=fact[i-1]*i%P;
        inv[N-1]=Pow(fact[N-1],P-2);for (int i=N-2;i>=0;i--) inv[i]=inv[i+1]*(i+1)%P;
        for (int i=1;i<=m;i++) f[0][i]=1;
        for (int i=1;i<=lg;i++)
            for (int j=1;j<=m;j++)
                for (int k=2;k*j<=m;k++) (f[i][j*k]+=f[i-1][j])%=P;
        for (int i=0;i<=min(lg,n-1);i++)
            for (int j=1;j<=m;j++) (ans+=f[i][j]*C(n-1,i))%=P;
        printf("%lld\n",ans);
    }
    View Code

    D

    范围很小,做法很暴力

    从低位到高位,设 f[i][j] 表示做到第 i 位,前面 i-1 位满足相消为 0 的方案数

    O(mlogm)

    #include <iostream>
    #include <cstdio>
    #include <cmath>
    using namespace std;
    typedef long long ll;
    const ll P=998244353;
    const int N=5e3+10;
    int n,m,lg;
    ll fact[N],inv[N],f[15][N];
    
    ll Pow(ll x,ll y) {ll ans=1;for (;y;y>>=1,x=x*x%P) if (y&1) ans=ans*x%P;return ans;}
    
    ll C(int n,int m) {return fact[n]*inv[n-m]%P*inv[m]%P;}
    
    int main() {
        scanf("%d%d",&n,&m);lg=log2(m);
        if (m&1) return printf("0"),0;
        fact[0]=1;for (int i=1;i<=n;i++) fact[i]=fact[i-1]*i%P;
        inv[n]=Pow(fact[n],P-2);for (int i=n-1;i>=0;i--) inv[i]=inv[i+1]*(i+1)%P;
        f[0][0]=1;
        for (int i=0,k=1;i<=lg;i++,k<<=1)
            for (int j=0;j<=m;j++) {
                for (int l=2;j+k*l<=m&&l<=n;l+=2) (f[i+1][j+k*l]+=f[i][j]*C(n,l)%P)%=P;
                (f[i+1][j]+=f[i][j])%=P;
            }
        printf("%lld\n",f[lg+1][m]);
    }
    View Code
  • 相关阅读:
    ubuntu 下的中文输入法的安装和配置- ibus
    数据分析-序列处理(2)
    数据分析创建数据框与数据获取(1)
    Python的函数与方法的区别
    Python3笔记015
    Python3笔记014
    Python3笔记013
    Python3笔记012
    Python3笔记011
    Python3笔记010
  • 原文地址:https://www.cnblogs.com/vagari/p/14594429.html
Copyright © 2020-2023  润新知