• 【学习笔记】[ARC145F] Modulo Sum of Increasing Sequences


    单位根反演好题。

    提示:是照搬的 这篇题解 的做法,只是加了一点小小的解释。

    首先,做等价变换:给第 i i i个位置加上 i − 1 i-1 i1,问题转化为了求单调递增序列,即从 [ 0 , N + M − 1 ] [0,N+M-1] [0,N+M1]中选 N N N不同的数,使得这些数模 mod ⁡ \operatorname{mod} mod的值为 k k k

    这事实上是一个二元 G F GF GF的问题。先不考虑选 N N N个数的限制,记 n = N + M n=N+M n=N+M,写出答案的生成函数形式: ∏ i = 0 n − 1 ( 1 + x i ) \prod_{i=0}^{n-1}(1+x^i) i=0n1(1+xi)

    k = mod ⁡ k=\operatorname{mod} k=mod,那么我们要求所有 i k + r ik+r ik+r项的系数和,这通常可以用单位根反演来解决。

    对于任意多项式 f ( x ) f(x) f(x),我们有:

    ∑ k ∣ i [ x i ] f ( x ) = ∑ i = 0 n − 1 [ x i ] f ( x ) 1 k ∑ j = 0 k − 1 w k i j = 1 k ∑ i = 0 n − 1 a i ∑ j = 0 k − 1 ( w k j ) i = 1 k ∑ j = 0 k − 1 ∑ i = 0 n − 1 a i ( w k j ) i = 1 k ∑ j = 0 k − 1 f ( w k j ) k|i[xi]f(x)=n1i=0[xi]f(x)1kk1j=0wijk=1kn1i=0aik1j=0(wjk)i=1kk1j=0n1i=0ai(wjk)i=1kk1j=0f(wjk) ki[xi]f(x)=i=0n1[xi]f(x)k1j=0k1wkij=k1i=0n1aij=0k1(wkj)i=k1j=0k1i=0n1ai(wkj)i=k1j=0k1f(wkj)

    类似的: ∑ [ x i k + r ] f ( x ) = 1 k ∑ j = 0 k − 1 w k − j r f ( w k j ) \sum[x^{ik+r}]f(x)=\frac{1}{k}\sum_{j=0}^{k-1}w_k^{-jr}f(w_k^j) [xik+r]f(x)=k1j=0k1wkjrf(wkj)

    注意这里的 k k k不是 2 2 2的次幂,因此不能直接计算。要想办法把单位根搞掉。

    注意到 x n − 1 = ∏ i = 0 n − 1 ( x − w n i ) x^n-1=\prod_{i=0}^{n-1}(x-w_n^i) xn1=i=0n1(xwni) x = − 1 x=-1 x=1,那么 ∏ i = 0 n − 1 ( w n i + 1 ) = 1 − ( − 1 ) n \prod_{i=0}^{n-1}(w_n^i+1)=1-(-1)^n i=0n1(wni+1)=1(1)n

    考虑 k ∣ n k|n kn的情况。 d = gcd ⁡ ( j , k ) d=\gcd(j,k) d=gcd(j,k),此时 gcd ⁡ ( j d , k d ) = 1 \gcd(\frac{j}{d},\frac{k}{d})=1 gcd(dj,dk)=1

    f ( w k j ) = ∏ i = 0 n − 1 ( 1 + w k i j ) = ∏ i = 0 k d − 1 ( 1 + w k d i ) n d k = ( 1 − ( − 1 ) k d ) n d k f(wjk)=n1i=0(1+wijk)=kd1i=0(1+wikd)ndk=(1(1)kd)ndk f(wkj)=i=0n1(1+wkij)=i=0dk1(1+wdki)knd=(1(1)dk)knd

    带入原式即: 1 k ∑ j = 0 k − 1 w k − j r ( 1 − ( − 1 ) k d ) n d k \frac{1}{k}\sum_{j=0}^{k-1}w_k^{-jr}(1-(-1)^{\frac{k}{d}})^{\frac{nd}{k}} k1j=0k1wkjr(1(1)dk)knd,现在考虑怎么把前面的单位根搞掉。看到 gcd ⁡ \gcd gcd考虑枚举 d d d,即:

    L H S = 1 k ∑ d ∣ k ( 1 − ( − 1 ) k d ) n d k ∑ gcd ⁡ ( j , k ) = d w k − j r LHS=\frac{1}{k}\sum_{d|k}(1-(-1)^{\frac{k}{d}})^{\frac{nd}{k}}\sum_{\gcd(j,k)=d}w_k^{-jr} LHS=k1dk(1(1)dk)kndgcd(j,k)=dwkjr

    后面那一坨看起来就很好化简:

    ∑ gcd ⁡ ( j , k ) = d w k − j r = ∑ i = 1 k d w k − i d r [ gcd ⁡ ( i , k d ) = 1 ] = ∑ i = 1 k d w k − i d r ∑ j ∣ gcd ⁡ ( i , k d ) μ ( j ) = ∑ j ∣ k d μ ( j ) ∑ i = 1 k d j w k − i j d r = ∑ j ∣ k d μ ( j ) ∑ i = 1 k d j w k d j − r i = ∑ j ∣ k d μ ( j ) [ k d j ∣ r ] gcd gcd(j,k)=dwkjr=i=1dkwkidr[gcd(i,dk)=1]=i=1dkwkidrjgcd(i,dk)μ(j)=jdkμ(j)i=1djkwkijdr=jdkμ(j)i=1djkwdjkri=jdkμ(j)[djkr]

    最后一步是 逆用单位根反演 。因此最终答案为:

    L H S = 1 k ∑ d ∣ k ( 1 − ( − 1 ) k d ) n d k g ( d , k ) LHS=k1dk(1(1)dk)kndg(d,k)

    其中 g ( d , k ) g(d,k) g(d,k)是固定的系数。现在考虑二元 G F GF GF,即 [ x i k + r y n ] ∏ i = 0 n − 1 ( 1 + x i y ) [x^{ik+r}y^n]\prod_{i=0}^{n-1}(1+x^iy) [xik+ryn]i=0n1(1+xiy)。前面的推导都一模一样(把 y y y当成参量来处理),不难验证答案为:

    L H S = 1 k ∑ d ∣ k ( 1 − ( − y ) k d ) n d k g ( d , k ) LHS=\frac{1}{k}\sum_{d|k}(1-(-y)^{\frac{k}{d}})^{\frac{nd}{k}}g(d,k) LHS=k1dk(1(y)dk)kndg(d,k)

    对于 n ∤ k n\nmid k nk的情况,可以将剩余的不足 k k k项暴力背包,即设 f i , j f_{i,j} fi,j表示选了 i i i个数,并且模 k k k等于 j j j的方案数。可以在 O ( k 3 ) O(k^3) O(k3)的时间内处理出来,最后合并答案也是 O ( k 3 ) O(k^3) O(k3)的。

    #include
    #define ll long long
    #define pb push_back
    #define fi first
    #define se second
    using namespace std;
    const int mod=998244353;
    const int N=505;
    const int M=2e6+5;
    int n,m,p,n2,mx;
    ll now[N][N];
    ll fac[M],inv[M],f[N],g[N][N],res[N];
    ll fpow(ll x,ll y=mod-2){
        ll z(1);
        for(;y;y>>=1){
            if(y&1)z=z*x%mod;
            x=x*x%mod;
        }return z;
    }
    void init(int n){
        fac[0]=1;for(int i=1;i<=n;i++)fac[i]=fac[i-1]*i%mod;
        inv[n]=fpow(fac[n]);for(int i=n;i>=1;i--)inv[i-1]=inv[i]*i%mod;
    }
    int mu[N],vs[N];
    int pr[N],cnt;
    void init2(int n){
        mu[1]=1;
        for(int i=2;i<=n;i++){
            if(vs[i]==0)pr[++cnt]=i,mu[i]=-1;
            for(int j=1;j<=cnt&&pr[j]<=n/i;j++){
                vs[i*pr[j]]=1;
                if(i%pr[j]==0){
                    mu[i*pr[j]]=0;
                    break;
                }mu[i*pr[j]]=-mu[i];
            }
        }
    }
    ll binom(int x,int y){
        if(x<0||y<0||x<y)return 0;
        return fac[x]*inv[y]%mod*inv[x-y]%mod;
    }
    void add(ll &x,ll y){
        x=(x+y)%mod;
    }
    vector<int>v;
    int main(){
        ios::sync_with_stdio(false);
        cin.tie(0),cout.tie(0);
        cin>>n>>m>>p,n2=n+m;
        init(n2),init2(p);
        mx=p*(n2/p);
        for(int i=1;i<=p;i++){
            if(p%i==0)v.pb(i);
        }
        for(int k=0;k<p;k++){
            for(auto d:v){
                for(auto j:v){
                    if(p/d%j==0&&k%(p/d/j)==0){
                        add(g[k][d],mu[j]*p/d/j);
                    }
                }
            }
        }
        now[0][0]=1;
        for(int i=mx;i<n2;i++){
            int s=i%p;
            for(int j=min(n2-mx,n);j>=1;j--){
                for(int k=0;k<p;k++){
                    add(now[j][k],now[j-1][(k-s+p)%p]);
                }
            }
        }
        for(int i=0;i<=min(n,n2-mx);i++){
            memset(f,0,sizeof f);
            for(auto d:v){
                if((n-i)%(p/d))continue;
                int t=(n-i)/(p/d);
                for(int k=0;k<p;k++){
                    if(p/d%2==1||t%2==0){
                        add(f[k],binom(d*mx/p,t)*g[k][d]);
                    }
                    else{
                        add(f[k],-binom(d*mx/p,t)*g[k][d]);
                    }
                }
            }
            for(int j=0;j<p;j++){
                for(int k=0;k<p;k++){
                    add(res[(j+k)%p],f[j]*now[i][k]);
                }
            }
        }for(int i=0;i<p;i++){
            res[i]=res[i]*fpow(p)%mod;
        }int tmp=(ll)n*(n-1)/2%p;
        for(int i=0;i<p;i++){
            cout<<(res[(i+tmp)%p]+mod)%mod<<" ";
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
  • 相关阅读:
    leetcode-23.合并K个升序链表
    【漏洞复现】某 NVR 视频存储管理设备远程命令执行
    时间序列分析(11)| 向量自回归模型(VAR模型)
    ET-B32C如何让屏幕常亮(屏幕不熄灭或待机状态)
    详解数据仓库之拉链表(原理、设计以及在Hive中的实现)
    179. 最大数
    word翻译-批量word翻译
    记录一次clickhouse报错max_query_size超过最大限制
    基于SqlSugar的开发框架循序渐进介绍(11)-- 使用TypeScript和Vue3的Setup语法糖编写页面和组件的总结
    大数据智能化-长视频领域
  • 原文地址:https://blog.csdn.net/cqbzlydd/article/details/133755766