題解 [HAOI2017]方案數
阿新 • • 發佈:2020-12-19
Solution
我們沒有障礙的時候很好做,直接設 \(f_{i,j,k}\) 表示到 \((x,y,z)\) \(x\) 有 \(i\) 位為 \(1\),\(y\) 有 \(j\) 位為 \(1\),\(z\) 有 \(k\) 位為 \(1\) 的方案數。轉移顯然。
考慮有障礙。我當時一直沒有注意到一個點導致一直沒有想出來。我們設 \(g_{i}\) 表示到第 \(i\) 個被禁止的點且不經過其他禁止點的方案數。可以得到轉移式:
\[g_{i}=f_{i}-\sum_{j} g_{j}\times f_{i-j} \]這樣是對的是因為不會經過兩個被禁止的點。
時間複雜度 \(\Theta(o^2)\)
Code
#include <bits/stdc++.h> using namespace std; #define Int register int #define int long long #define MAXN 75 template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;} template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);} template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');} #define ll long long #define MAXM 10005 int g[MAXM]; ll n,m,r,tot; int get (ll x){int res = 0;while (x) res += (x & 1),x >>= 1;return res;} struct node{ ll x,y,z; int a,b,c,ind; void init(){a = get (x),b = get (y),c = get (z);} void putin(){read (x,y,z),init();} bool operator < (const node &fuc){return x == fuc.x ? (y == fuc.y ? z < fuc.z : y < fuc.y) : x < fuc.x;} }p[MAXM]; #define mod 998244353 int C[MAXN][MAXN],f[MAXN][MAXN][MAXN]; int mul (int a,int b){return 1ll * a * b % mod;} int dec (int a,int b){return a >= b ? a - b : a + mod - b;} int add (int a,int b){return a + b >= mod ? a + b - mod : a + b;} signed main(){ read (n,m,r,tot); for (Int i = 1;i <= tot;++ i) p[i].putin(),p[i].ind = i; p[++ tot] = node {n,m,r},p[tot].init(); C[0][0] = 1; for (Int i = 1;i <= 65;++ i){ C[i][0] = 1; for (Int j = 1;j <= i;++ j) C[i][j] = add (C[i - 1][j],C[i - 1][j - 1]); } f[0][0][0] = 1; for (Int i = 0;i <= 65;++ i) for (Int j = 0;j <= 65;++ j) for (Int k = 0;k <= 65;++ k){ for (Int x = 1;x <= i;++ x) f[i][j][k] = add (f[i][j][k],mul (f[i - x][j][k],C[i][x])); for (Int x = 1;x <= j;++ x) f[i][j][k] = add (f[i][j][k],mul (f[i][j - x][k],C[j][x])); for (Int x = 1;x <= k;++ x) f[i][j][k] = add (f[i][j][k],mul (f[i][j][k - x],C[k][x])); } sort (p + 1,p + tot + 1); for (Int i = 1;i <= tot;++ i){ g[i] = f[p[i].a][p[i].b][p[i].c]; for (Int j = 1;j < i;++ j){ if (((p[i].x & p[j].x) == p[j].x) && ((p[i].y & p[j].y) == p[j].y) && ((p[i].z & p[j].z) == p[j].z)) g[i] = dec (g[i],mul (g[j],f[p[i].a - p[j].a][p[i].b - p[j].b][p[i].c - p[j].c])); } } write (g[tot]),putchar ('\n'); return 0; }