• Atcoder 124E Pass to Next


    Problem Statement

    (N) people called Person (1,2,…,N) are standing in a circle.

    For each (1≤i≤N−1), Person (i)'s neighbor to the right is Person (i+1), and Person (N)'s neighbor to the right is Person (1).

    Person (i) initially has (a_{i}) balls.

    They will do the following procedure just once.

    • Each person chooses some (possibly zero) of the balls they have.
    • Then, each person simultaneously hands the chosen balls to the neighbor to the right.
    • Now, make a sequence of length (N), where the (i)-th term is the number of balls Person (i) has at the moment.

    Let (S) be the set of all sequences that can result from the procedure. For example, when (a=(1,1,1)), we have (S={(0,1,2),(0,2,1),(1,0,2),(1,1,1),(1,2,0),(2,0,1),(2,1,0)})

    Compute (∑_{x∈S}∏^{N}_{i=1}x_i), modulo 998244353.

    Constraints

    • All values in input are integers.
    • (3≤N≤10^5)
    • (0≤a_i≤10^9)

    Input

    Input is given from Standard Input in the following format:

    N
    a1 a2 ⋯⋯ aN
    

    Output

    Print (∑_{x∈S}∏^{N}_{i=1}x_i), modulo 998244353.


    Sample Input 1 Copy

    Copy

    3
    1 1 1
    
    Sample Output 1 Copy

    Copy

    1
    
    • We have (S={(0,1,2),(0,2,1),(1,0,2),(1,1,1),(1,2,0),(2,0,1),(2,1,0)})
    • (∑_{x∈S}∏^{N}_{i=1}x_i) is 11.

    Sample Input 2 Copy

    Copy

    3
    2 1 1
    
    Sample Output 2 Copy

    Copy

    6
    

    Sample Input 3 Copy

    Copy

    20
    5644 493 8410 8455 7843 9140 3812 2801 3725 6361 2307 1522 1177 844 654 6489 3875 3920 7832 5768
    
    Sample Output 3 Copy

    Copy

    864609205
    
    • Be sure to compute it modulo 998244353.

    题目翻译

    有n个人,环形排列,每个人有(a_i)个球,每个人同一事件给下一个传递任意数量自己的球。

    (S)不相同的最终状态的集合,求(∑_{x∈S}∏^{N}_{i=1}x_i)

    题目解析

    首先是,考虑什么情况下两种不同的传递方案可以得到相同的结果

    显然传递序列(1,1,2,2)(2,2,3,3)的最终状态是等价的

    归纳得出:两次传递等价满足传递序列的差分序列相同,则最终状态等价

    上面两个传递序列差分序列均为(-1,0,1,0)

    如何除去等价的传递?如果传递序列,如果最小值大于0,那么一定存在更小的等价传递序列

    故可以得出最终方案数:(prod_{i=1}^{n}{a_i+1}-prod_{i=1}^{n}{a_i})

    但是原题并不是求最终方案数,但是最终方案数的计算可以启发:利用容斥原理排除等价的状态

    第二个重点是答案需求的表达式,首先(∏^{N}_{i=1}x_i)可以表示为第(i)个人各自在自己最后拥有的(x_i)球中选一个的方案数

    这样原题就转换为了分类讨论第(i)个人选的一个球分别是前面的人,还是自己的方案数。可以用动态规划解决

    (f[i][j](j=0/1)),当(j=0)时,(f[i][0])表示第 (i)个人从自己原本有的球中选球,前 (i−1)个人选球的方案数(不考虑自己)。当(j=1)时,(f[i][1])表示第 (i)个人从前面的球中选球,前 (i)个人选球的方案数(考虑自己的方案数)

    之所以区分(j=0)(j=1)不同来源的表达方式,是为了独立不同来源的球

    同时注意:前一个人传多少给下一个人与下一个人传出多少之间没有关系。也就是说,传递都是同时发生的

    这里设(S(n)=sum_{i=1}^n i=frac{n(n+1)}{2}) (g(n)=sum_{i=1}^{n}{i^2}={frac{n(n+1)(2n+1)}{6}})

    (f[i][0]->f[i+1][0])因为(f[i][0])没有计算第(i)个人的方案,故(f[i+1][0]+=f[i][0]*S(a_i))

    (f[i][1]->f[i+1][0])因为算上了第(i)个人方案,只需算上传球方案(f[i+1][0]+=f[i][1]*(a_i+1))

    (f[i][0]->f[i+1][1])因为没有计算第(i)个人,故需要计算(i)(i+1)的方案,假如第(i)个人剩(k)个球,第(i+1)人拿(a_i-k)个球,总方案为(sum_{k=1}^{a_i}{k*(a_i-k)}=a_i*S(a_i)-g(a_i)),有(f[i+1][1]+=f[i][0]*(a_i*S(a_i)-g(a_i)))

    (f[i][1]->f[i+1][1])只要计算第(i+1)个人从第(i)个人获得球的方案,(f[i+1][1]+=f[i][1]*S(a_i))

    上面的转移已经体现了区分(j=0)方案不包括(i)自己和(j=1)方案包括(i)的作用,当第(i)个人选择自己原有的球,第(i+1)人选择(i)传递的球,那么显然此时两个人的方案应该一起计算。同时(i+1)选择(i)传递的球,(i)选择(i-1)传递的球

    由于转移是一个环,(i=n)需要转移到(i=1)。则需要先钦定第1个人是选自己的球还是选第 n 个人传的球(初值设为1,另一个设为0),然后转移一圈。如果初始化钦定 $f[1][0]=1,f[1][1]=0 $ ,那么最终答案就是(f[1][0]-1),反过来是一样的。

    最后考虑传球最小值不为0的容斥,在调用一次DP并在模拟传球过程中限制传球数不为0。将之前DP的答案减去约束后得到的即为满足不等价条件的方案数

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    using namespace std;
    typedef long long ll;
    int n,a[100005];
    int Mod=998244353;
    ll f[100005][2],inv2,inv3;
    ll qpow(ll x,int k){
        ll res=1;
        while (k){
            if (k&1) res=res*x%Mod;
            x=x*x%Mod;
            k>>=1;
        }
        return res;
    }
    ll dp(int init,int zero){//init表示dp[1][]的初值,zero表示是否不允许0传递   
        memset(f,0,sizeof(f));
        f[1][0]=init;f[1][1]=init^1;
        for (int i=1;i<=n;i++){
            int to=i%n+1;
            ll s=(a[i]-zero+Mod)%Mod;
            //转移时,剩余值为a[i]不合法,因为剩余a[i]代表转移为0
            ll s1=s*(s+1)%Mod*inv2%Mod;
            f[to][0]=(f[to][0]+f[i][0]*s1%Mod)%Mod;
            f[to][0]=(f[to][0]+f[i][1]*(s+1)%Mod)%Mod;
            if (zero) s++;
            //因为对于f[to][1]的转移,传递值0的情况计数为0不会计入结果
            //to选的球是来自i的球,所以此处表示传递值的a[i]合法
            ll s2=s*(s+1)%Mod*inv2%Mod;
            ll s3=s*(s+1)%Mod*(s*2+1)%Mod*inv2%Mod*inv3%Mod;
            f[to][1]=(f[to][1]+f[i][0]*(s2*s%Mod-s3+Mod)%Mod)%Mod;
            f[to][1]=(f[to][1]+f[i][1]*s2%Mod)%Mod;
        }
        if (init) {
            f[1][0]-=1;
            return (f[1][0]+Mod)%Mod;
        }else {
            f[1][1]-=1;
            return (f[1][1]+Mod)%Mod;
        }
    }
    int main(){
        cin>>n;
        inv2=qpow(2,Mod-2);inv3=qpow(3,Mod-2);
        for (int i=1;i<=n;i++){
            scanf("%d",&a[i]);
        }
        cout<<((dp(0,0)+dp(1,0))%Mod-(dp(0,1)+dp(1,1))%Mod+Mod)%Mod;
    }
    
  • 相关阅读:
    C#根据IP地址和子网掩码计算广播地址
    关于ZIP大文件压缩
    JVM内存的设置
    Eclipse下内存溢出错误(OutOfMemoryError)
    实体化视图的使用心得(转)
    Java 调用cmd.exe命令
    select 操作选中添加、删除操作Javascript
    quartz定时任务时间设置
    手动安装 MyEclipse6.5 FindBugs
    App Transport Security has blocked a cleartext HTTP (http://) resource load since it is insecure.-解决办法
  • 原文地址:https://www.cnblogs.com/Y-E-T-I/p/15134553.html
Copyright © 2020-2023  润新知