説明] [タイトルを
持っている\(N- \) OK \(M \)行からテーブルの列、\(0 \)に\(N-1 \)カラムから数\(0 \)に(M- \ 1 \)番号。
各グリッドはエネルギーで保存されています。最初に、\(I \)行\(J \)記憶グリッドのカラム\((I \ \テキスト{ XOR} \ J)\) エネルギー。したがって、テーブル全体の総エネルギーが格納されます。
\(\和\ limits_ ^ {N-1} {I = 0} \和\ limits_ {J = 0} ^ {M-1}(I \ \テキスト{XOR} \ J)\)
時間が経つにつれて、エネルギーグリッドが徐々に削減されます。単位時間後、各グリッドは、エネルギー削減する\(1 \) 。もちろん、パワーグリッドが減少している(0 \)\あなたは削減されることはありません。
換言すれば、\(K \)時間単位後に、テーブル全体の総エネルギー貯蔵です。
\(\和\ limits_ ^ {iが0 =} {N-1} \和\ limits_ {J = 0} ^ {M-1} MAX((I \ XOR \ J)-k 0)\)
テーブルを考えると、見つける\(K \)それに蓄えられたエネルギーの後の合計時間単位。
総エネルギーを出力する、大きいかもしれないので(P \)\モジュロ。
問題の解決策
すべての元の式=(I ^ J)> kの最初の元ストリッパー満たす(I ^ j)の和である - すべて満たす(I ^ j)は>数kの番号(i、j)が* kと
DPは、(i ^ J)> K、及びそれらの(I ^ j)を満たす(i、j)のデジタル数を用いて解くことができる数の合計であります
具体的な手法は、メモリ・レコードを検索することである(のLiMn、LIMM、LIMK \ \ ) 現在列挙バイナリの前にそれぞれ\(I \)カードが満杯であるかどうかの位置、\(N、M \)境界と上(\ K)\下限
私はこの事は、クリアなデジタル基本ルーチンDP DOはないのか分かりません
私は、(i ^ j)の和の条件を満たすように保存されているどのように多くの第二の条件を満足する最初の預金ペアDPの答えを維持するために使用されます
注意モジュロ
[コード]
#include <bits/stdc++.h>
#define mp make_pair
using namespace std;
typedef long long ll;
typedef pair<ll, ll> pii;
inline ll read() {
ll x = 0, f = 1; char ch = getchar();
for (; ch > '9' || ch < '0'; ch = getchar()) if (ch == '-') f = -1;
for (; ch <= '9' && ch >= '0'; ch = getchar()) x = (x << 1) + (x << 3) + (ch ^ '0');
return x * f;
}
ll t, n, m, k, mod, mx;
pii dp[105][2][2][2], ans;
bool vis[105][2][2][2];
inline ll getl(ll x) {
ll ret = 0;
while (x) ret++, x >>= 1;
return ret;
}
pii dfs(ll d, bool limn, bool limm, bool limk) {
if (d > mx) return mp(1, 0);
if (vis[d][limn][limm][limk]) return dp[d][limn][limm][limk];
ll N = (n>>(mx-d)) & 1, M = (m>>(mx-d)) & 1, K = (k>>(mx-d)) & 1;
for (ll i = 0; i <= (limn ? N : 1); i++) {
for (ll j = 0; j <= (limm ? M : 1); j++) {
if (limk && (i^j) < K) continue;
pii res = dfs(d+1, limn&&(i==N), limm&&(j==M), limk&&((i^j)==K));
dp[d][limn][limm][limk].first = (dp[d][limn][limm][limk].first + res.first) % mod;
dp[d][limn][limm][limk].second = (((dp[d][limn][limm][limk].second + res.second) % mod) + (1ll << (mx - d)) * (i^j) % mod * res.first % mod) % mod;
}
}
vis[d][limn][limm][limk] = true;
return dp[d][limn][limm][limk];
}
int main() {
t = read();
while (t--) {
n = read(); m = read(); k = read(); mod = read();
n--, m--;
memset(dp, 0, sizeof(dp)); memset(vis, 0, sizeof(vis));
mx = max(max(getl(n), getl(m)), getl(k));
ans = dfs(1, 1, 1, 1);
printf("%lld\n", (ans.second - k % mod * ans.first % mod + mod) % mod);
}
return 0;
}