JZOJ 5990. Bear(斜线dp)

版权声明:博主写博客也挺不容易,转载当然阔以,记得先吱一声~ https://blog.csdn.net/Cold_Chair/article/details/86499888

Description:

在这里插入图片描述
n<=12,m<=30

题解:

很容易想到一种一行一行的dp,我们觉得n太小了,想一列一列做,发现不行。

然后脑洞打开,直接斜着dp,发现就没有了。

Code:

#include<cstdio>
#include<cstring>
#define pp printf
#define ll long long
#define fo(i, x, y) for(int i = x; i <= y; i ++)
#define fd(i, x, y) for(int i = x; i >= y; i --)
using namespace std;

const int N = 31;

int n, m, mo, a2[14];
int a[N * N][2], a0, b[N * N][2], b0, x, y;
int o, m2;
ll f[2][1 << 13], g[2][1 << 13];

#define w(x, y) ((x) >> (y) & 1)

int zz(int k, int d) {
	int nn = (x == n || y == 1) ? 0 : w(k, x) * a2[n];
	if(w(k, x)) k -= a2[x];
	if(w(k, n)) k -= a2[n];
	if(d == 1) k += a2[x - 1];
	if(d == 2) k += a2[x];
	return k + nn;
}

int main() {
	freopen("bear.in", "r", stdin);
	freopen("bear.out", "w", stdout);
	a2[0] = 1; fo(i, 1, 13) a2[i] = a2[i - 1] << 1;
	scanf("%d %d %d", &n, &m, &mo);
	fo(i, 1, n) a[++ a0][0] = i, a[a0][1] = 1;
	fo(j, 2, m) a[++ a0][0] = n, a[a0][1] = j;
	m2 = a2[n + 1] - 1;
	f[o][0] = 1;
	fo(i, 1, a0 - 1) {
		b0 = 0;
		x = a[i][0], y = a[i][1];
		
		while(x > 0 && y <= m)
			b[++ b0][0] = x, b[b0][1] = y, x --, y ++;
		fd(j, b0, 1) {
			memset(f[!o], 0, sizeof f[!o]);
			memset(g[!o], 0, sizeof g[!o]);
			x = b[j][0], y = b[j][1];
			fo(k, 0, m2) if(f[o][k]) {
				f[o][k] %= mo;
				g[o][k] %= mo;
				int z1 = w(k, n), z2 = y == m ? 1 : w(k, x - 1), z3 = x == n ? 1 : 0; 
				if(z1 || z2 && z3) { 
					int nk = zz(k, 0);
					f[!o][nk] += f[o][k] * 2;
					g[!o][nk] += g[o][k] * 2;
				} else
				if(z2 && !z3) {					
					int nk = zz(k, 2); 
					f[!o][nk] += f[o][k] * 2;
					g[!o][nk] += (g[o][k] + f[o][k]) * 2;
				} else
				if(!z2 && z3) {
					int nk = zz(k, 1);
					f[!o][nk] += f[o][k] * 2;
					g[!o][nk] += (g[o][k] + f[o][k]) * 2;
				} else {
					int nk = zz(k, 1);
					f[!o][nk] += f[o][k];
					g[!o][nk] += (g[o][k] + f[o][k]);
					nk = zz(k, 2);
					f[!o][nk] += f[o][k];
					g[!o][nk] += (g[o][k] + f[o][k]);
				}
			}
			o = !o;
		}
		memset(f[!o], 0, sizeof f[!o]);
		memset(g[!o], 0, sizeof g[!o]);
		x = a[i + 1][0], y = a[i + 1][1];
		while(x > 0 && y <= m) x --, y ++;
		int p = x;
		fo(k, 0, m2) if(f[o][k]) {
			int nk = k - w(k, p) * a2[p] + a2[n] * w(k, p);
			f[!o][nk] += f[o][k];
			g[!o][nk] += g[o][k];
		}
		o = !o;
	}
	ll ans = 0;
	fo(k, 0, m2) ans = (ans + g[o][k]) % mo;
	pp("%lld\n", ans * 2 % mo);
}

猜你喜欢

转载自blog.csdn.net/Cold_Chair/article/details/86499888