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<bits/stdc++.h>
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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章