暑假集训CSP提高模拟10

暑假集训CSP提高模拟10

组题人: @worldvanquisher

\(T1\) P170. 黑暗型高松灯 \(0pts\)

  • 原题: CF1025G Company Acquisitions
  • 科技题目,直接贺官方题解了。

    考虑势能函数。如果我们使得每操作一步期望势能 \(-1\),那么初势能减末势能就是答案。

    设一个点有 \(x\) 个儿子的势能为 \(f(x)\),那么考虑现在选中两个儿子个数为 \(x,y\) 的:

    \[\frac 12(f(x+1)+yf(0))+\frac 12(f(y+1)+xf(0))-f(x)-f(y)=-1 \]

    不妨令 \(f(0)=0\) (其实好像是随意定的),那么同构一下得到 \(f(x)=1-2^x\),初减末即可。

    其实是有应用条件的,但是大多数时候是你觉得能用就能用。详见 https://www.cnblogs.com/C202044zxy/p/16340757.html 第一道例题

    部分分尊重原题。

\(T2\) P168. 速度型高松灯 \(95pts\)

  • 原题: luogu P3216 [HNOI2011] 数学作业

  • \(F_{n}=\begin{bmatrix} n & f_{n} & 1 \end{bmatrix}\) ,容易有 \(\begin{aligned} F_{n} &= F_{10^{k-1}-1} \times \begin{bmatrix} 1 & 1 & 0 \\ 0 & 10^{k} & 0 \\ 1 & 1 & 1 \end{bmatrix}^{n-(10^{k-1}-1)} \end{aligned}\) ,其中 \(n \in [10^{k-1},10^{k})\)

  • 因为 \(k \in [0, \left\lfloor \log_{10}n \right\rfloor+2]\) ,每个 \(k\) 单独算就行了。

    点击查看代码
    #define ll __int128_t
    struct Matrix
    {
        ll ma[5][5];
        Matrix()
        {
            memset(ma,0,sizeof(ma));
        }
    }f,a;
    Matrix mul(Matrix a,Matrix b,ll n,ll m,ll k,ll p)
    {
        Matrix c;
        for(ll i=1;i<=n;i++)
        {
            for(ll j=1;j<=k;j++)
            {
                for(ll h=1;h<=m;h++)
                {
                    c.ma[i][j]=(c.ma[i][j]+a.ma[i][h]*b.ma[h][j]%p)%p;
                }
            }
        }
        return c;
    }
    Matrix qpow(Matrix a,ll b,ll p,ll n)
    {
        Matrix ans;
        for(ll i=1;i<=n;i++)
        {
            ans.ma[i][i]=1;
        }
        while(b)
        {
            if(b&1)
            {
                ans=mul(ans,a,n,n,n,p);
            }
            b>>=1;
            a=mul(a,a,n,n,n,p);
        }
        return ans;
    }
    int main()
    {
        ll b,p,n=1,m=3,k=3,i;
        scanf("%lld%lld",&b,&p);
        f.ma[1][3]=1;
        for(i=10;i/10<=b;i*=10)
        {
            a.ma[1][1]=a.ma[1][2]=a.ma[3][1]=a.ma[3][2]=a.ma[3][3]=1;
            a.ma[2][2]=i%p;
            f=mul(f,qpow(a,min(i,b+1)-i/10,p,m),n,m,k,p);
        }
        printf("%lld\n",f.ma[1][2]);
        return 0;
    }
    

\(T3\) P169. 力量型高松灯 \(0pts\)

  • 原题: luogu P6156 简单题 | luogu P6222 「P6156 简单题」加强版

  • 部分分

    • \(20pts\) :暴力枚举即可,时间复杂度为 \(O(n^{2} \log n+n \log k)\) ,可以使用扩展欧拉定理优化,使时间复杂度为 \(O(n^{2} \log^{2}n +n \log \sqrt{p})\)
  • 正解

    • 因涉及变量重名问题,以下所写的 \(m\) 指本题的 \(k\)
    • 推式子,有 \(\begin{aligned} &\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{n}(i+j)^{m}\mu^{2}(\gcd(i,j))\gcd(i,j) \\ &=\sum\limits_{k=1}^{n}\mu^{2}(k)k\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{n}(i+j)^{m} [\gcd(i,j)=k] \\ &=\sum\limits_{k=1}^{n}\mu^{2}(k)k\sum\limits_{i=1}^{\left\lfloor \frac{n}{k} \right\rfloor}\sum\limits_{j=1}^{\left\lfloor \frac{n}{k} \right\rfloor}(ik+jk)^{m} [\gcd(i,j)=1] \\ &=\sum\limits_{k=1}^{n}\mu^{2}(k)k^{m+1}\sum\limits_{i=1}^{\left\lfloor \frac{n}{k} \right\rfloor}\sum\limits_{j=1}^{\left\lfloor \frac{n}{k} \right\rfloor}(i+j)^{m}\sum\limits_{d|\gcd(i,j)}\mu(d) \\ &=\sum\limits_{k=1}^{n}\mu^{2}(k)k^{m+1}\sum\limits_{d=1}^{\left\lfloor \frac{n}{k} \right\rfloor}\mu(d)\sum\limits_{i=1}^{\left\lfloor \frac{n}{kd} \right\rfloor}\sum\limits_{j=1}^{\left\lfloor \frac{n}{kd} \right\rfloor}(id+jd)^{m} \\ &=\sum\limits_{k=1}^{n}\mu^{2}(k)k^{m+1}\sum\limits_{d=1}^{\left\lfloor \frac{n}{k} \right\rfloor}\mu(d)d^{m}\sum\limits_{i=1}^{\left\lfloor \frac{n}{kd} \right\rfloor}\sum\limits_{j=1}^{\left\lfloor \frac{n}{kd} \right\rfloor}(i+j)^{m} \\ &=\sum\limits_{T=1}^{n}T^{m}\sum\limits_{k|T}\mu^{2}(k)\mu(\frac{T}{k})k\sum\limits_{i=1}^{\left\lfloor \frac{n}{T} \right\rfloor}\sum\limits_{j=1}^{\left\lfloor \frac{n}{T} \right\rfloor} (i+j)^{m} \end{aligned}\)
    • \(\begin{cases} s(n)=\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{n}(i+j)^{m} \\ h(i)=i^{m} \\ f(n)=\sum\limits_{i=1}^{n}h(i) \\ g(n)=\sum\limits_{i=1}^{n}f(i) \end{cases}\) ,数形结合有 \(\begin{aligned} &s(n) \\ &=s(n-1)+f(2n)+f(2n-1)-2f(n) \\ &=g(2n)-2g(n) \end{aligned}\) 。每个数单独计算其 \(h\) 值时间复杂度不可接受,我们发现 \(h\) 为完全积性函数,可以线筛预处理,也可以使用扩展欧拉定理优化。
    • 原式可以写作 \(\begin{aligned} &=\sum\limits_{T=1}^{n}s(\left\lfloor \frac{n}{T} \right\rfloor)T^{m}\sum\limits_{k|T}\mu^{2}(k)\mu(\frac{T}{k})k \end{aligned}\)
    • \(w(n)=n^{m}\sum\limits_{d|n}\mu^{2}(d)\mu(\frac{n}{d})d\) ,显然 \(w\) 为积性函数。现在把关注点放在后面的 \(\mu^{2}(k)\mu(\frac{T}{k})\) 上,二者必须同时为 \(1\) 才对答案产生贡献,即 \(k,\frac{T}{k}\) 均没有平方质因子,那么 \(T\) 就不能有一个质因子的次数 \(\ge 3\) ,线筛时记录下次数即可。
      • \(\begin{cases} w(p)=p^{m}(p-1) \\ w(p^{2})=p^{2m} \times (-p) \end{cases}\)
    • 维护 \(w\) 的前缀和,整除分块维护 \(\frac{n}{T}\) 即可。
    • 略卡空间,无用空间回收利用。
    点击查看代码
    const ll p=998244353,phi=998244352;
    ll prime[10000010],h[10000010],w[10000010],len=0;
    bool vis[10000010];
    ll qpow(ll a,ll b,ll p)
    {
        ll ans=1;
        while(b)
        {
            if(b&1)
            {
                ans=ans*a%p;
            }
            b>>=1;
            a=a*a%p;
        }
        return ans;
    }
    void isprime(ll n,ll k)
    {
        memset(vis,0,sizeof(vis));
        h[1]=w[1]=1;
        for(ll i=2;i<=2*n;i++)
        {
            if(vis[i]==0)
            {
                len++;
                prime[len]=i;
                h[i]=qpow(i,k,p);
                w[i]=i-1;
            }
            for(ll j=1;j<=len&&i*prime[j]<=2*n;j++)
            {
                vis[i*prime[j]]=1;
                h[i*prime[j]]=h[i]*h[prime[j]]%p;
                if(i%prime[j]==0)
                {
                    w[i*prime[j]]=((i/prime[j])%prime[j]!=0)*w[i/prime[j]]*(-prime[j]+p)%p;	
                    break;
                }
                else
                {
                    w[i*prime[j]]=w[i]*(prime[j]-1)%p;//乘以 w[prime[j]]
                }
            }
        }
        for(ll i=1;i<=n;i++)
        {
            w[i]=(w[i-1]+w[i]*h[i]%p)%p;//求 w 的前缀和
        }
        for(ll i=1;i<=2*n;i++)
        {
            h[i]=(h[i-1]+h[i])%p;//求 f
        }
        for(ll i=1;i<=2*n;i++)
        {
            h[i]=(h[i-1]+h[i])%p;//求 g
        }
    }
    ll s(ll x)
    {
        return (h[2*x]-2*h[x]%p+p)%p;//求 s
    }
    ll ask(ll n)
    {
        ll ans=0,l,r;
        for(l=1,r;l<=n;l=r+1)
        {
            r=(n/l>=1)?min(n/(n/l),n):n;
            ans=(ans+(w[r]-w[l-1]+p)%p*s(n/l)%p)%p;
        }
        return ans;
    }
    int main()
    {
        ll n,k;
        cin>>n>>k;
        k%=phi;//扩展欧拉定理
        isprime(n,k);
        cout<<ask(n)<<endl;
        return 0;
    }
    

\(T4\) P167. 高松灯 \(100pts\)

  • 数位 \(DP\) 板子。

    点击查看代码
    ll a[25],f[25][180],sum=0;
    ll divide(ll n,ll a[])
    {
        ll len=0;
        while(n)
        {
            len++;
            a[len]=n%10;
            n/=10;
        }
        return len;
    }
    ll dfs(ll pos,ll pre,ll lead,ll limit)
    {
        if(pos<=0)
        {
            return pre;
        }
        if(f[pos][pre]!=-1&&lead==0&&limit==0)
        {
            return f[pos][pre];
        }
        ll ans=0,maxx=(limit==0)?9:a[pos],i;
        for(i=0;i<=maxx;i++)
        {
            ans=max(ans,dfs(pos-1,pre+i,(i==0)*lead,(i==maxx)*limit));
        }
        return (lead==0&&limit==0)?f[pos][pre]=ans:ans;
    }
    ll ask(ll n)
    {
        ll len=divide(n,a);
        return dfs(len,0,1,1);
    }
    int main()
    {
        ll n;
        cin>>n;
        memset(f,-1,sizeof(f));
        cout<<ask(n)<<endl;
        return 0;
    }
    
  • 最终答案只会来自两种情况,一种是原数,一种是首位放 \(1\) 其余全是 \(9\) ,二者取 \(\max\) 即可。

总结

  • 赛时历程:先溜了一眼题, \(T1\) 直接弃掉, \(T2\) 之前做过但细节有点多, \(T3\) 可以骗点分, \(T4\) 之前做过类似的且几乎是数位 \(DP\) 纯板子。遂先写 \(T4\) ,因为太过着急导致少打了个负号,少搜了许多状态,花 \(20 \min\) 才调出来;然后写 \(T2\) ,式子因为之前写的时候有点麻烦,遂写了个简单点的,但还是在调细节,调了 \(1h\) ;接着是 \(T3\) ,推到最后发现漏了一个 \(\gcd(i,j)=1\) 导致预处理直接死掉,交了个暴力上去; \(T1\) 特判了两种情况。
  • \(T2\) 枚举 \(10^{k}\) 时炸 long long 了,挂了 \(5pts\)
  • \(T3\) 暴力预处理 \(\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{n}[\gcd(i,j)=1] \times (i+j)^{k}\) 时空间开大了,再次 \(MLE\) ,挂了 \(20pts\)

后记

  • 难度不单调递增。

  • 因赛时能过 \(T1\) 太过逆天,所以奖励也很逆天。

  • @joke3579 学长让 @int_R 上台评价这场比赛,还开玩笑说要不少于六百字,且还拍视频给 @worldvanquisher

posted @ 2024-07-28 14:54  hzoi_Shadow  阅读(91)  评论(4编辑  收藏  举报
扩大
缩小