CF293B Distinct Paths

CF293B Distinct Paths

洛谷评测传送门

题目描述

You have a rectangular n×mn×m -cell board. Some cells are already painted some of kk colors. You need to paint each uncolored cell one of the kk colors so that any path from the upper left square to the lower right one doesn't contain any two cells of the same color. The path can go only along side-adjacent cells and can only go down or right.

Print the number of possible paintings modulo 10000000071000000007 (10^{9}+7)(109+7) .

输入格式

The first line contains three integers n,m,kn,m,k (1<=n,m<=1000,1<=k<=10)(1<=n,m<=1000,1<=k<=10) . The next nn lines contain mm integers each — the board. The first of them contains mm uppermost cells of the board from the left to the right and the second one contains mm cells from the second uppermost row and so on. If a number in a line equals 0, then the corresponding cell isn't painted. Otherwise, this number represents the initial color of the board cell — an integer from 1 to kk .

Consider all colors numbered from 1 to kk in some manner.

输出格式

Print the number of possible paintings modulo 10000000071000000007 (10^{9}+7)(109+7) .

题意翻译

【问题描述】

给定一个 n*m 的矩形色板,有 k 种不同的颜料,有些格子已经填上了某种颜色,现在 需要将其他格子也填上颜色,使得从左上角到右下角的任意路径经过的格子都不会出现两种 及以上相同的颜色。路径只能沿着相邻的格子,且只能向下或者向右。 计算所有可能的方案,结果对 1000000007 (10^9 + 7)求模。

【输入数据】

第一行,三个整数 n, m, k (1 ≤ n, m ≤ 1000, 1 ≤ k ≤ 10); 接下来 n 行,每行包含 m 个整数,表示颜色。其中 0 表示未涂色,非 0 表示颜色的编号, 颜色编号为 1 到 k。

【输出数据】

扫描二维码关注公众号,回复: 7678004 查看本文章

一行,一个整数,表示涂色方案对 1000000007 (10^9 + 7)求模的结果。

由 @hicc0305 提供翻译

输入输出样例

输入 #1复制

输出 #1复制

输入 #2复制

输出 #2复制

输入 #3复制

输出 #3复制

输入 #4复制

输出 #4复制

题解:

2019.10.29模拟赛T2 20分场

一开始毫无思路。

后来发现?咦?如果左上和右下的数(非零)一模一样的话,那就可以直接输出0了。

再后来发现?咦?如果矩阵长宽减一小于\(k\),那么也显然不合法。

那这题会不会太简单了?绝壁不会

询问出题人被一顿惨\(Diss\),坚定了我的看法一般猜到出题人的小心思出题人都会Diss

所以用两个特判加一个错误的搜索拿了20分。

正确的搜索加剪枝应该是:

如果搜索到一半,发现步数比颜色还多,那么就直接return。

可如果你只这么做,你就会发现:两个颜色的先后次序也会决定方案数的不同。

所以我们在搜索的时候直接进行排列的乘法,就可以剪掉很多枝桠。

就是:可行性剪枝+排除等效冗余

关于剪枝方式,有兴趣了解更多的小伙伴可以参考本蒟蒻的这篇博客:

关于剪枝的方式

代码如下:

#include<cstdio>
using namespace std;
const int mod=1e9+7;
const int maxn=1010;
int n,m,k,ans;
int map[maxn][maxn],cnt[20];
int f[50][50];
int dfs(int x,int y)
{
    if(y==m+1)
        return dfs(x+1,1);
    if(x==n+1)
        return 1;
    int num=0,flag=0,ret=0,last=0;
    f[x][y]=f[x-1][y]|f[x][y-1];
    for(int i=1;i<=k;i++)
        if(!(f[x][y]&(1<<i-1)))
            num++;
    if(num<n+m-x-y+1)
        return 0;
    if(!map[x][y])
    {
        for(int i=1;i<=k;i++)
        {
            if(!(f[x][y]&(1<<i-1)))
            {
                if(!cnt[i])
                {
                    if(flag)
                        ret=(ret+last)%mod;
                    else
                    {
                        flag=1;
                        cnt[i]++;
                        f[x][y]|=1<<i-1;
                        last=dfs(x,y+1);
                        f[x][y]^=1<<i-1;
                        cnt[i]--;
                        ret=(ret+last)%mod;
                    }
                    continue;
                }
                cnt[i]++;
                f[x][y]|=1<<i-1;
                ret+=dfs(x,y+1);
                f[x][y]^=1<<i-1;
                cnt[i]--;
                ret%=mod;
            }
        }
    }
    else
    {
        if(!(f[x][y]&(1<<(map[x][y]-1))))
        {
            f[x][y]|=1<<map[x][y]-1;
            ret+=dfs(x,y+1);
            f[x][y]^=1<<map[x][y]-1;
            ret%=mod;
        }
    }
    return ret;
}
int main()
{
    scanf("%d%d%d",&n,&m,&k);
    if(n+m-1>k)
    {
        puts("0");
        return 0;
    }
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
            scanf("%d",&map[i][j]);
            cnt[map[i][j]]++;
        }
    ans=dfs(1,1);
    printf("%d",ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/fusiwei/p/11760612.html