CF 111D - Petya and Coloring

题目大意:

用k种颜色涂 n*m 的矩形,要求  如果  1~i  和 i+1~m  所用的颜色种类一样多,不要求颜色一样、


思路:

可以推出  第一列和第m列所用的颜色数量是一样的。

证明 :如果a[1~1]=i a[m~m]=j (i<j)
那么a[1~1]=i<j<=a[2~m] 所以不满足


然后中间的m-2列  是不能出现新颜色的。也就是必须是第一列和第m列的颜色不然会导致两边不相等了。


用dp[i] 表示用i种颜色且必须是i种颜色涂在n个格子上的方式。

那么 dp[i] = i^n-segma(C(i,j)*dp[j])   1<=j<i   也就是减去只涂了少于i种的情况


然后我们开始处理,

当m==1的时候  就是k^n

当m==2的时候  左边i种  右边 i种  就是 (C(k,i)*dp[i])^2...

当m==3的时候  

要枚举相同的颜色的数量i  和不同的颜色的数量j

第一列在k个里选i个   然后在k-i个里选择选择j个    第m列则要在k-i-j里再选j个

然后再涂上去   就是乘以 dp[i+j]...


#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
typedef long long LL;
using namespace std;
const LL mod=1000000007;
LL fac[1000005]={1},rev[1000005]={1};
LL dp[1005];
LL pow_mod(LL a,LL i,LL n)
{
    if(i==0)return 1%n;
    LL temp=pow_mod(a,i>>1,n);
    temp=temp*temp%n;
    if(i&1)temp=temp*a%n;
    return temp;
}
void init()
{
    for(int i=1;i<=1000000;i++)
    fac[i]=fac[i-1]*i%mod,rev[i]=pow_mod(fac[i],mod-2,mod);
}
LL C(int n,int m)
{
    return (fac[n]*rev[m]%mod)*rev[n-m]%mod;
}

int main()
{
    init();
    int n,m,k;
    scanf("%d%d%d",&n,&m,&k);
    if(m==1)
    {
        printf("%I64d\n",pow_mod(k,n,mod));
        return 0;
    }

    for(int i=1;i<=n && i<=k;i++)
    {
        dp[i]=pow_mod(i,n,mod);
        for(int j=1;j<i;j++)
        {
            dp[i]=(dp[i]-C(i,j)*dp[j]%mod)+mod;
            dp[i]%=mod;
        }
    }

    LL ans=0;
    if(m==2)
    {
        for(int i=1;i<=n && i<=k;i++)
        {
            ans=(ans+(((dp[i]*dp[i]%mod)*C(k,i)%mod)*C(k,i))%mod)%mod;
        }
        printf("%I64d\n",ans);
    }
    else
    {
        for(int i=1;i<=n && i<=k;i++)
        {
            for(int j=0;2*j+i<=k && i+j<=n;j++)
            {
                LL tmp=dp[i+j]*dp[i+j]%mod;
                tmp=((tmp*C(k,i)%mod)*C(k-i,j)%mod)*C(k-i-j,j)%mod;
                tmp=(tmp*pow_mod(i,n*(m-2),mod))%mod;
                ans=(ans+tmp)%mod;
            }
        }
        printf("%I64d\n",ans);
    }
    return 0;
}

   

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
解法:贪心算法 如果两个字符串不相等,那么它们必定至少有一位不一样。考虑对于这一位,我们应该对字符串 a 进行哪种操作,才能使得它更接近于字符串 b。 首先,我们可以通过交换字符串 a 中的两个数字,使得这一位变为我们想要的数字。如果我们把这一位变成了 b 中的数字,那么显然这一位就不需要再进行修改了。因此,我们只需要考虑把这一位变成 a 中的数字 4 或 7。 如果我们把这一位变成 a 中的数字,则需要执行一次操作;如果我们把这一位变成 a 中的数字,则需要执行一次操作。那么,我们应该采取哪种操作呢? 我们可以贪心地想,如果我们把这一位变成 a 中的数字,那么这一位和 b 中的数字就越相似,那么接下来的操作就越容易执行。因此,我们应该选择将这一位变成 a 中的数字,从而尽可能地增加和 b 相同的数字的数量。 实现时,我们可以从左到右扫描字符串 a 和 b,统计它们不同的位置的数量。对于每个不同的位置,我们都可以选择将这一位变成 4 或 7,然后更新 a 中数字 4 和 7 的数量。最终,我们就可以得到将字符串 a 转换为字符串 b 所需的最少操作数。 时间复杂度 字符串 a 和 b 的长度为 n,我们需要扫描一遍字符串并统计数字 4 和 7 的数量,因此时间复杂度为 O(n)。 空间复杂度 我们只需要存储数字 4 和 7 的数量,因此空间复杂度为 O(1)。 Python 代码

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值