2020.06 浙江理工大学校赛 B.喜羊羊破密码-六门锁

题目链接

文章目录

  • 题目描述
  • 思路
  • 代码

题目描述

有n行2列的格子阵,每个格子最多能填0~9 9个数,在初始状态下有的格子已经填了数字不能再改变,在满足每3行共6个格子的和始终相同的情况下,有多少种解法,答案对1e9+7取模

思路

还可提前特判一下,若这六个和的值大于54,那么一定无解。
可以注意到,第1,4,7…行两个格子之和大小一定相同,第2,5,8行两个子大小一定相同,第3,6,9…行两格子大小一定相同。所以我先计算出第一行格子的最小值和最大值,第二行格子所要求的最小值和最大值,第三行格子所要求的最小值和最大值,然后预处理一下所满足的要求组,最后对每行进行方法计算。
如果一行数字为8且两个格子都为空,那么就有9种方法。
如果一个格子为空或者都不为空,都当作只有一种方法。

代码

#include
using namespace std;
 
typedef long long LL;
 
const int mod = 1e9 + 7;
const int N = 1e5 + 10;
int a[N][2];
bool st[N][2];  // 判断某行某列这个数值是否可以更改
LL res = 0;
int down[N], up[N];		// 记录第i行的最大值和最小值
int maxnum[3], minnum[3];	// 因为都成等差数列,其实就是0,1,2三行的大小比较
struct node {
    int u, v, w;
};
vector<node> cacl;
 
void solve()
{
    int n, k, m;
    scanf("%d%d%d", &n, &k, &m);
 
    if(k > 54 || n * 2 == m) {
        puts("0");
        return;
    }
 
    for(int i = 1; i <= m; i++) {
        int x, y, num;
        scanf("%d%d%d", &x, &y, &num);
        a[x][y] = num;
        st[x][y] = 1;
    }
 
    // 计算最大最小值
    memset(maxnum, 0x3f, sizeof maxnum);
    for(int i = 0; i < n; i++) {
        down[i] = a[i][0] + a[i][1];
        if(!st[i][0] && !st[i][1]) up[i] = min(18, k);
        else if(st[i][0] && !st[i][1]) up[i] = 18 - 9 + a[i][0] ;
        else if(!st[i][0] && st[i][1]) up[i] = 18 - 9 + a[i][1];
        else up[i] = down[i];
        maxnum[i % 3] = min(maxnum[i % 3], up[i]);
        minnum[i % 3] = max(minnum[i % 3], down[i]);
    }
 
    // 预处理所有满足的组
    for(int u = minnum[0]; u <= maxnum[0]; u++) {
        for(int v = minnum[1]; v <= maxnum[1]; v++) {
            for(int w = minnum[2]; w <= maxnum[2]; w++) {
                if(u + w + v == k) cacl.push_back({u, v, w});
            }
        }
    }
 
    // 方法数计算
    LL res = 0;
    for(int i = 0; i < cacl.size(); i++) {
        int u = cacl[i].u, v = cacl[i].v, w = cacl[i].w;
        LL num = 1;
        for(int j = 0; j < n; j += 3) {
            if(!st[j][0] && !st[j][1]) {
                if(u < 10) num = num * (u + 1) % mod;
                else num = num * (18 - u + 1) % mod;
            }
        }
        for(int j = 1; j < n; j += 3) {
            if(!st[j][0] && !st[j][1]) {
                if(v < 10) num = num * (v + 1) % mod;
                else num = num * (18 - v + 1) % mod;
            }
        }
        for(int j = 2; j < n; j += 3) {
            if(w == 0) break;
            if(!st[j][0] && !st[j][1]) {
                if(w < 10) num = num * (w + 1) % mod;
                else num = num * (18 - w + 1) % mod;
            }
        }
        res = (res + num) % mod;
    }
    printf("%lld\n", res);
}
 
int main()
{
    //freopen("in.txt", "r", stdin);
    solve();
    return 0;
}

你可能感兴趣的:(比赛)