Petya and Coloring

/*
http://codeforces.com/problemset/problem/111/D

题目简化为求i个块砖中从k种颜色中选j种,每种颜色至少涂1次的方案数
程序1
dp[i][j]表示前i块砖在k种不同的颜色中用了j种颜色的方案数
dp[i][j]=(dp[i][j]+dp[i-1][j-1]*(k-j+1))%mod;
dp[i][j]=(dp[i][j]+dp[i-1][j]*j)%mod;
程序2
dp[i][j]表示前i块砖用j种颜色的方案数,不考虑具体颜色.只看重种数
相当于是一种模式
dp[i][j]=(dp[i][j]+dp[i-1][j-1])%mod;
dp[i][j]=(dp[i][j]+dp[i-1][j]*j)%mod;

 (dp[i][j]*fac[j]%mod)*Cal(k,j)%mod(程序2的dp)=dp[i][j](程序1的dp)
  */

#include<stdio.h>
#include<string.h>

typedef __int64 lld;
const int mod=1000000007;
const int maxn=1005;
lld C[maxn][maxn];
lld dp[maxn][maxn];
lld fac[1000005];
int n,m,k;

void init(){
    int i,j;
    fac[0]=1;
    for(i=1;i<1000005;i++)
        fac[i]=(fac[i-1]*i)%mod;
}

lld Mul(lld a,lld b){
    lld ret=1;
    while(b){
        if(b&1)ret=ret*a%mod; 
        b>>=1;
        a=a*a%mod;
    }
    return ret;
}

lld Cal(int x,int y){
    lld tmp=fac[x]*Mul(fac[x-y]*fac[y]%mod,mod-2)%mod;
    return tmp; 
}

int main(){
    int i,j;
    init();
    while(scanf("%d%d%d",&n,&m,&k)!=EOF){
        memset(dp,0,sizeof(dp));

        dp[0][0]=1;
        for(i=1;i<=n;i++){
            for(j=1;j<=i&&j<=k;j++){
				if(k>=j-1)
                dp[i][j]=(dp[i][j]+dp[i-1][j-1]*(k-j+1))%mod;
                dp[i][j]=(dp[i][j]+dp[i-1][j]*j)%mod;
            }
        }
		/*
		for(i=1;i<=15;i++){
            for(j=1;j<=i;j++){
				printf("%I64d ",dp[i][j]);
			}
			puts("");
        }*/
        lld ans=0;
        if(m==1){
            printf("%I64d\n",Mul(k,n));
        }else{
            for(i=1;i<=n && i<=k;i++){//最左最右个有i
                for(j=(m!=2);j<=i;j++)//中间m-2的部分用j种
                    if(k>=2*i-j){
                    lld tp=Cal(i,j)*Mul(j,n*(m-2))%mod;
                    lld tg=dp[n][i]*dp[n][i]%mod;
					lld tf=Cal(k-i,i-j)*Mul(Cal(k,i),mod-2)%mod;
                    ans=(ans+((tp*tf%mod)*tg%mod))%mod;
                }   
            }
            printf("%I64d\n",ans);
        }
    
    }
    return 0;
}


/*

#include<stdio.h>
#include<string.h>

typedef __int64 lld;
const int mod=1000000007;
const int maxn=1005;
lld C[maxn][maxn];
lld dp[maxn][maxn];
lld fac[1000005];
int n,m,k;

void init(){
    int i,j;
    fac[0]=1;
    for(i=1;i<1000005;i++)
        fac[i]=fac[i-1]*i%mod;
}

lld Mul(lld a,lld b){
    lld ret=1;
    while(b){
        if(b&1)ret=ret*a%mod; 
        b>>=1;
        a=a*a%mod;
    }
    return ret;
}

lld Cal(int x,int y){
    lld tmp=fac[x]*Mul(fac[x-y]*fac[y]%mod,mod-2)%mod;
    return tmp; 
}

int main(){
    int i,j;
    init();
    while(scanf("%d%d%d",&n,&m,&k)!=EOF){
        memset(dp,0,sizeof(dp));

        dp[0][0]=1;
        for(i=1;i<=n;i++){
            for(j=1;j<=i;j++){
                dp[i][j]=(dp[i][j]+dp[i-1][j-1])%mod;
                dp[i][j]=(dp[i][j]+dp[i-1][j]*j)%mod;
            }
        }
	***************
		for(i=1;i<=15;i++){
            for(j=1;j<=i;j++){
				if(k>=j)
				printf("%I64d ",(dp[i][j]*fac[j]%mod)*Cal(k,j)%mod);
				else
				printf("0 ");
			}
			puts("");
        }
	***************
        lld ans=0;
        if(m==1){
            printf("%I64d\n",Mul(k,n));
        }else{
            for(i=1;i<=n && i<=k;i++){//最左最右个有i
                for(j=(m!=2);j<=i;j++)//都有的j
                    if(k>=2*i-j){
                    lld tp=Cal(k,j)*Mul(j,n*(m-2))%mod;
                    lld tf=Cal(k-j,i-j)*Cal(k-i,i-j)%mod;
                    lld tg=((dp[n][i]*dp[n][i]%mod)*(fac[i]*fac[i]%mod))%mod;
                    ans=(ans+((tp*tf%mod)*tg%mod))%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、付费专栏及课程。

余额充值