1 条题解

  • 0
    @ 2025-8-24 21:57:28

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar pluszero
    **

    搬运于2025-08-24 21:57:28,当前版本为作者最后更新于2018-03-20 17:27:19,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    这题是一道很经典的DP,还用了一点点逆向思维。

    题目大意:有n个格子,用m种颜色覆盖,每次只能覆盖k个格子,原来有颜色也可以覆盖,问一共有多少种最终状态?

    题意看上去貌似有点像数学题,但仔细思索就会发现题目只是要求至少有一个长度为k的相同颜色的块。刚开始以为可以用数学方法,将一个长度为k的块单独拿出来,当成一格,然后算排列组合。交上去只过了2个点。仔细想发现有很多重复,于是就放弃了。

    后来经过老师的点拨,发现可以用逆向思维来做,先用排列组合算出没有k这个限制条件的所有可能方案,即n的m次方。再算出不符合方案的情况,也就是没有一个长度至少为k的相同颜色的块减去即可。想要算出不符合的方案总数也很简单,一个简单的一维DP就行了,因为我们规定不能有长度超过k的块,所以最多只有连续k-1个格子颜色相同。所以DP方程为:

    f[0]=1

    当i<k时,f[i]=f[i-1]*m;

    当i>k时,f[i]=(f[i-k+1]+...+f[i-1])*(m-1); (第i-k位必须与第i-k+1位到第i位不同,所以乘m-1)

    最后答案即为总方案数减去不符合方案数。

    程序:

    #include<bits/stdc++.h>
    using namespace std;
    
    long long f[1000001];
    
    int main()
    {
        int n,m,k;
        scanf("%d%d%d",&n,&m,&k);
        long long sum1=1,sum=0;
        for(int i=1;i<=n;i++) sum1=(sum1*m)%1000000007;
        f[0]=1;
        for(int i=1;i<k;i++) 
        {
            f[i]=(f[i-1]*m)%1000000007;
            sum=(sum+f[i])%1000000007;
        }
        for(int i=k;i<=n;i++)
        {
            f[i]=(sum*(m-1))%1000000007;
            sum=(sum+f[i]+1000000007-f[i-k+1])%1000000007;
        }
        printf("%lld",(sum1+1000000007-f[n])%1000000007);
        return 0;
    }
    
    • 1

    信息

    ID
    3133
    时间
    1000ms
    内存
    125MiB
    难度
    5
    标签
    递交数
    0
    已通过
    0
    上传者