長さがkkであることが保証されている限り、@ vjudgekまたはk + 1 k + 1k+1の回文を
押すと、最後のkkを保存できますKビットステータス、転送するたびに妥当かどうかを判断するだけ
コード:
#include <bits/stdc++.h>
#define maxn 410
#define maxm 2010
#define qy 1000000007
using namespace std;
int power[25], n, m, dp[maxn][maxm];
inline int read(){
int s = 0, w = 1;
char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') w = -1;
for (; isdigit(c); c = getchar()) s = (s << 1) + (s << 3) + (c ^ 48);
return s * w;
}
bool calc(int x, int y){
return !(x > 0 && y > 0 || x == 0 && y == 0); }
bool check(int x, int y){
int flag = 0;
if (calc(x & power[m - 1], y)) flag = 1;
if (!flag)
for (int i = m - 1; i; --i)
if (calc(x & power[i - 1], x & power[m - i - 1])){
flag = 1; break; }
return flag;
}
bool check1(int x, int y){
int flag = 0;
if (calc(x & power[m - 2], y)) flag = 1;
if (!flag){
for (int i = m - 2; i; --i)
if (calc(x & power[i - 1], x & power[m - 1 - i - 1])){
flag = 1; break; }
}
return flag;
}
int main(){
int Q = read();
power[0] = 1;
for (int i = 1; i <= 20; ++i) power[i] = power[i - 1] << 1;
// m = 3; printf("%d\n", check1(2, 1));
while (Q--){
n = read(), m = read();
if (m < 2){
puts("0"); continue; }
// printf("%d\n", ((2 << 1) | 1) & (power[m] - 1));
for (int i = 1; i <= n; ++i)
for (int j = 0; j <= power[m] - 1; ++j) dp[i][j] = 0;
dp[1][0] = dp[1][1] = 1;
for (int i = 1; i < n; ++i)
for (int j = 0; j <= power[min(m, i)] - 1; ++j){
// printf("modest%d\n", dp[i][j]);
for (int k = 0; k <= 1; ++k)
if (i < m - 1 || (i == m - 1 && check1(j, k)) || i >= m && check1(j, k) && check(j, k)){
if ((dp[i + 1][((j << 1) | k) & (power[m] - 1)] += dp[i][j]) >= qy)
dp[i + 1][((j << 1) | k) & (power[m] - 1)] -= qy;
// printf("dp[%d][%d]=%d\n", i + 1, ((j << 1) | k) & (power[m] - 1), dp[i + 1][((j << 1) | k) & (power[m] - 1)]);
}
}
int ans = 0;
for (int i = 0; i < power[min(m, i)]; ++i) if ((ans += dp[n][i]) >= qy) ans -= qy;
printf("%d\n", ans);
}
return 0;
}