QOJ.ac
QOJ
ID | Problem | Submitter | Result | Time | Memory | Language | File size | Submit time | Judge time |
---|---|---|---|---|---|---|---|---|---|
#283356 | #2576. 麻将 | yhk1001 | 100 ✓ | 1031ms | 17960kb | C++14 | 3.8kb | 2023-12-14 15:24:39 | 2023-12-14 15:24:40 |
Judging History
answer
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <map>
#include <queue>
using namespace std;
const int N = 100, M = N << 2;
const int SZ = 2100;
const long long P = 998244353;
int n, m;
int cnt[N + 5];
struct Info
{
int dp[3][3];//(i - 1, i), i
Info()
{
memset(dp, -1, sizeof(dp));//illegal statement, unreachable
}
bool win()
{
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
if (dp[i][j] >= 4)
return true;
return false;
}
void add(int x)
{
int tmp[3][3];
memset(tmp, -1, sizeof(tmp));
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
{
if (dp[i][j] == -1)
continue;
for (int shun = 0; shun <= x - i - j && shun < 3; shun++)//i, i + 1, i + 2
tmp[j][shun] = max(tmp[j][shun], dp[i][j] + i + (x - i - j - shun) / 3);
}
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
tmp[i][j] = min(tmp[i][j], 4);//to simplify automaton
memcpy(dp, tmp, sizeof(dp));
return ;
}
void tomax(const Info& info)
{
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
dp[i][j] = max(dp[i][j], info.dp[i][j]);
return ;
}
};
struct State
{
Info info[2];//que tou
int pairs = 0;//7 pairs
void add(int x)
{
info[1].add(x);
if (x >= 2)
{
Info tmp = info[0];//should init tmp.pairs !
tmp.add(x - 2);
info[1].tomax(tmp);
}
info[0].add(x);
pairs += (x >= 2);
return ;
}
bool win()
{
return info[1].win() || pairs >= 7;
}
bool operator < (const State& state) const
{
for (int t = 0; t < 2; t++)
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
if (info[t].dp[i][j] != state.info[t].dp[i][j])
return info[t].dp[i][j] < state.info[t].dp[i][j];
return pairs < state.pairs;
}
};
map<State, int> id;
int tot;
queue<State> q;
int g[SZ + 5][5];
void build()
{
State st;
st.info[0].dp[0][0] = 0;
id[st] = ++tot;
q.push(st);
while (!q.empty())
{
State u = q.front();
q.pop();
int idu = id[u];
for (int x = 0; x <= 4; x++)
{
State v = u;
v.add(x);
if (!v.win() && !id[v])//winner node: 0
{
id[v] = ++tot;
q.push(v);
}
g[idu][x] = id[v];
}
}
return ;
}
long long fac[M + 5], inv[M + 5];
long long ksm(long long d, long long u)
{
long long res = 1;
while (u)
{
if (u & 1)
res = res * d % P;
u >>= 1;
d = d * d % P;
}
return res;
}
void initC()
{
fac[0] = 1;
for (int i = 1; i <= m; i++)
fac[i] = fac[i - 1] * i % P;
inv[m] = ksm(fac[m], P - 2);
for (int i = m - 1; i >= 0; i--)
inv[i] = inv[i + 1] * (i + 1) % P;
return ;
}
long long C(int x, int y)
{
if (x < y)
return 0ll;
return fac[x] * inv[y] % P * inv[x - y] % P;
}
long long dp[2][M + 5][SZ + 5];//i cards, at node u
int main()
{
// freopen("mahjong.in", "r", stdin);
// freopen("mahjong.out", "w", stdout);
scanf("%d", &n);
m = 4 * n;
for (int i = 1, w, t; i <= 13; i++)
{
scanf("%d%d", &w, &t);
cnt[w]++;
}
build();
initC();
int p = 0;
dp[0][0][1] = 1;
for (int num = 1; num <= n; num++)
{
for (int i = 0; i <= (num - 1) * 4; i++)//at most (num - 1) * 4 cards, run faster
for (int u = 1; u <= tot; u++)
{
for (int to = cnt[num]; to <= 4 && i + to <= m; to++)
{
int v = g[u][to];
dp[p ^ 1][i + to][v] = (dp[p ^ 1][i + to][v] +
dp[p][i][u] * C(4 - cnt[num], to - cnt[num]) % P) % P;
}
}
memset(dp[p], 0, sizeof(dp[p]));
p ^= 1;
}
long long ans = 1;//all situations need at least 1 card
for (int i = 14; i <= m; i++)
{
long long sum = 0;
for (int u = 1; u <= tot; u++)
sum = (sum + dp[p][i][u]) % P;
sum = sum * fac[i - 13] % P * fac[m - i] % P * inv[m - 13] % P;
ans = (ans + sum) % P;
}
printf("%lld\n", ans);
return 0;
}
Details
Tip: Click on the bar to expand more detailed information
Test #1:
score: 10
Accepted
time: 5ms
memory: 17700kb
input:
5 1 1 1 2 1 3 1 4 2 1 3 1 3 2 3 3 3 4 5 1 5 2 5 3 5 4
output:
570425346
result:
ok single line: '570425346'
Test #2:
score: 10
Accepted
time: 7ms
memory: 17616kb
input:
5 1 3 2 4 4 3 5 3 3 1 5 4 4 2 1 4 4 4 3 3 3 2 1 1 2 2
output:
713031682
result:
ok single line: '713031682'
Test #3:
score: 10
Accepted
time: 26ms
memory: 17692kb
input:
13 1 3 12 1 12 2 1 4 13 3 13 2 3 2 13 1 1 1 3 4 3 3 1 2 12 3
output:
868236068
result:
ok single line: '868236068'
Test #4:
score: 10
Accepted
time: 21ms
memory: 17632kb
input:
13 1 1 13 1 2 3 1 3 3 1 3 4 2 1 13 4 1 4 12 2 13 3 12 3 3 2
output:
234399821
result:
ok single line: '234399821'
Test #5:
score: 10
Accepted
time: 22ms
memory: 17668kb
input:
13 2 3 2 1 12 2 13 2 2 2 1 2 13 3 12 4 13 4 3 4 3 1 12 3 1 3
output:
892522858
result:
ok single line: '892522858'
Test #6:
score: 10
Accepted
time: 695ms
memory: 17928kb
input:
81 1 1 2 1 3 1 4 1 5 1 6 1 7 1 8 1 9 1 10 1 11 1 12 1 13 1
output:
152635587
result:
ok single line: '152635587'
Test #7:
score: 10
Accepted
time: 923ms
memory: 17616kb
input:
94 1 1 2 1 3 1 4 1 5 1 6 1 7 1 8 1 9 1 10 1 11 1 12 1 13 1
output:
339459976
result:
ok single line: '339459976'
Test #8:
score: 10
Accepted
time: 963ms
memory: 17628kb
input:
96 1 2 1 3 1 4 1 1 2 2 2 3 2 4 2 1 3 2 3 3 3 4 3 1 4 2
output:
230028597
result:
ok single line: '230028597'
Test #9:
score: 10
Accepted
time: 722ms
memory: 17960kb
input:
83 1 2 1 3 1 4 1 1 2 2 2 3 2 4 2 1 3 2 3 3 3 4 3 1 4 2
output:
967250236
result:
ok single line: '967250236'
Test #10:
score: 10
Accepted
time: 1031ms
memory: 17676kb
input:
100 67 1 26 4 12 4 11 4 30 4 29 1 1 4 13 3 30 1 64 2 63 1 20 2 32 4
output:
345132636
result:
ok single line: '345132636'
Extra Test:
score: 0
Extra Test Passed