AtCoder Regular Contest 116(A-D)

A、Odd vs Even

  • editorial

    已知对于给定数字\(n\),他的因子可以表示成\(\prod\limits_{i=1}^{m}p_i^{cnt_i}\),其中\(p_i\)是n的素因子,\(cnt_i \in [0,a_i]\), \(a_i\)是满足\([n \mod p_i^{a_i} = 0]\)这个条件的最大值。

    故知若\(2^{a_i}\)中的\(a_i\)大于1时,偶因子多于奇因子个数;两者相等时,偶因子等于奇因子个数;否则,偶因子少于奇因子个数。

  • code

    #include<bits/stdc++.h>
    using namespace std;
    
    typedef long long ll;
    int main()
    {
        int t;
        scanf("%d", &t);
        while(t--)
        {
            ll n;
            scanf("%lld", &n);
            if(n % 4 == 0)
                puts("Even");
            else if(n % 2 == 0 )
                puts("Same");
            else
                puts("Odd");
        }
        return 0;
    }
    

B、Products of Min-Max

  • editorial

    首先我们对该序列进行排序,发现就可以固定两端,中间是否选择,共有\(2^{max(0,j-i+1)}\)中选择,故答案为

    \[\sum\limits_{i=1}^n\sum\limits_{j=i}^na_i*a_j*2^{max(0,j-i-1)}=\sum\limits_{i=1}^na_i*\sum\limits_{j=i}^na_j*2^{max(0,j-i-1)} =\sum\limits_{i=1}^na_i*\sum\limits_{j=i+1}^na_j*2^{j-i-1}+\sum\limits_{i=1}^na_i^2 \]

    观察式子发现

    \(\sum\limits_{j=i}a_j*2^{j-i}=2*\sum\limits_{j=i+1}a_j*2^{j-i}+a_i\)

    故我们从后往前计算。

  • code

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int NMAX = 2e5 + 10;
    const int MOD = 998244353;
     
    int a[NMAX];
    int main()
    {
        int n;
        scanf("%d", &n);
        ll ans = 0, ant;
        for(int i = 1;i <= n;i++)   
        {
            scanf("%d", a + i);
            ans = (ans + 1ll*a[i]*a[i]%MOD)%MOD;
        }
        sort(a + 1, a + 1 + n);
        ant = a[n];
        for(int i = n-1;i >= 1;i--)
        {
            ans = (ans + ant*a[i]%MOD)%MOD;
            ant = (ant*2%MOD + a[i])%MOD;
        }
        printf("%lld\n", ans);
        return 0;
    }
    

C、Multiple Sequences

  • editorial

    对于整数\(m\),连续的因子序列(因子序列中元素互不相等),最大长度为\(\lfloor\log_2m\rfloor\),故进行dp,\(dp[i][j]\)表示最后一位数字,当前序列长度为\(i\)的可能情况。

    而对于原问题的序列我们可以通过我们的序列进行扩展,即将长度为\(i\)的序列扩展成长度为\(n\),即可以想象把长度为\(n\)的序列划分为\(i\)段,用插空法求出有\((n-1,i-1)\)种方式,故答案为\(\sum\limits_{i=1}^{20}(n-1,i-1)*(\sum\limits_{j=1}^mdp[i][j])\)

  • code

    #include<bits/stdc++.h>
     
    using namespace std;
    const int NMAX = 2e5 + 10;
    const int MOD = 998244353;
    typedef long long ll;
     
    ll dp[20][NMAX], sum[20];
    ll f[NMAX],finv[NMAX];
    ll fast_pow(ll a,ll n)
    {
        ll ans = 1;
        while(n)
        {
            if(n&1) ans = (ans * a)%MOD;
            a = (a * a)%MOD;
            n >>= 1;
        }
        return ans;
    }
    ll C(ll n,ll m)
    {
    	return (n<0||m<0||n<m)?0:f[n]*(finv[m])%mod*finv[n-m]%mod;
    }
    void init()
    {
        f[0]=1;
        for(int i=1;i< NMAX;i++)
            f[i]=f[i-1]*i%mod;
        finv[NMAX-1] = fast_pow(f[NMAX-1],mod-2);
        for (int i=NMAX-1; i > 0; i--)
            finv[i-1]=finv[i]*i%mod;
    }	
    int main()
    {
        int n, m;
        init();
        scanf("%d%d", &n, &m);
        for(int i = 1;i <= m;i++)   dp[1][i] = 1;
        sum[1] = m%MOD;
        for(int j = 2;j < 20;j++)
        {
            for(int i = 1;i <= m;i++)
                for(int k = 2*i; k <= m;k += i)
                    dp[j][k] = (dp[j][k] + dp[j-1][i])%MOD;
            for(int i = 1;i <= m;i++)
                sum[j] = (sum[j] + dp[j][i])%MOD;
        }
        
        ll ans = 0;        
        for(int i = 1;i < 20;i++)
            ans = (ans + C(n-1, i-1)*sum[i]%MOD)%MOD;  
        printf("%lld\n", ans);
        return 0;
    }
    

D、Wanna Win The Game

  • editorial
    官方题解
    \(\sum A_i\)为偶数时,\(Xor A_i\)才可能存在情况数,对于所有的\(A_i\)二进制,固定位的\(1\)的个数必然为偶数。那我们从低位往高位开始,构造序列\(A\)
    定义\(dp[i]\)\(m=i\)的答案,首先构造最后一位,即对于偶数\(m\),将\(m\)\(1\)放到\(n\)个位置(保证一个位置至多只有一个一),共有\((n, m)\)中方案。用之前的方案数来更新当前的情况,即在原来的序列每个元素左移一位,然后选择\(2j\)\(1\),分别加到序列\(A\)中,故有转移方程如下:

\[ dp[i*2+j] = 1ll*(dp[(i<<1)+j] + 1ll*dp[i]*C[n][j] \bmod MOD) \bmod MOD \iff j\equiv0\pmod{2} \]

  • code

    #include <bits/stdc++.h>
    using namespace std;
    
    const int MOD = 998244353;
    const int NMAX = 5e3 + 5;
    
    typedef long long ll;
    
    int C[NMAX][NMAX];
    int dp[NMAX];
    void init()
    {
        C[0][0] = 1;
        for(int i = 1;i < NMAX;i++)
        {
            C[i][0] = 1;
            for(int j = 1;j <= i;j++)
                C[i][j] = (C[i-1][j] + C[i-1][j-1])%MOD;
        }
    }
    
    int main()
    {
        init();
        int n, m;
        scanf("%d%d", &n, &m);
        for(int i = 2;i <= m;i += 2)
            dp[i] = C[n][i];
        for(int i = 1;i <= m;i++)
            for(int j = 0;(i<<1)+j <= m;j += 2)
                dp[i*2+j] = 1ll*(dp[(i<<1)+j] + 1ll*dp[i]*C[n][j]%MOD)%MOD;
        printf("%d\n", dp[m]);
        return 0;
    }
    
posted @ 2021-03-30 09:29  jadelemon  阅读(63)  评论(0编辑  收藏  举报