题意:
T组数据,每组数据有一个9*9的数独,数独初始全为 0/1, 0表示无限制,1表示该位置不能放1,问合法数独方案数(模998244353)
样例:
1
101101010
010000100
100100100
001001000
111011100
100100100
111010100
010101011
101101010
ans:915672442
吐槽:
这题我花了一个小时剪枝跑了5h没跑出来(捂脸
题解:
有一个很厉害的公式:
a
n
s
=
ans=
ans=数独总合法数*当前1可填的合法方案数/1可填的总合法方案
数独总合法数=样例中1的总填法/样例输出=719935075(取模后)
同理可得1可填的合法方案数=46656,求出逆元就ok了
所以只需要暴搜出“当前1可填的合法方案数”就行了。
第一次见到用样例推结论的题233333
代码很短题目很难。
// by Balloons
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define mpr make_pair
#define debug() puts("okkkkkkkk")
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
using namespace std;
typedef long long LL;
const int inf = 1 << 30;
const int n=9;
const int i_love_zlf=804434861;
const int maxn=15;
int T;
char s[maxn+5][maxn+5];
int a[maxn][maxn];
int cnt=0;
int c[maxn],su[maxn+5][maxn+5];
void dfs(int now){
if(now==n+1){++cnt;return ;}
for(int i=1;i<=n;i++){
if(!c[i]&&su[(now-1)/3][(i-1)/3]==0&&!a[now][i]){
c[i]=su[(now-1)/3][(i-1)/3]=1;
dfs(now+1);
c[i]=su[(now-1)/3][(i-1)/3]=0;
}
}
}
int main(){
scanf("%d",&T);
while(T--){
for(int i=1;i<=n;i++)scanf("%s",s[i]+1);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)a[i][j]=s[i][j]-'0';
cnt=0;
dfs(1);
printf("%d\n",1ll*i_love_zlf*cnt%998244353);
}
return 0;
}