【XSY3209】RGB Sequence

题目

传送门

解法

(f_{i, j, k})表示有(i)个红石块, (j)个绿宝石块, (k)个钻石块
可以转移到(f_{p+1, j, k})(f_{i, p+1,k })(f_{i, j, p+1})(p)(max(i, j, k))

代码

#pragma GCC optimize(3)
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <algorithm>

using namespace std;

const int mod = 1000000007;

const int N = 310;

const int M = 310;

struct node
{	int a, b;
	node() { }
	node(int _1, int _2) : a(_1), b(_2) { }
} list[M];

int head[N], nxt[M], tot;

inline void init()
{	memset(head, -1, sizeof(head));
	tot = 0;
}

inline void link(int x, int y, int z)
{	list[tot] = node(y, z);
	nxt[tot] = head[x];
	head[x] = tot++;
}

inline int max(int x, int y) { return x > y ? x : y; }

inline int Plus(int a, int b) { return a + b >= mod ? a + b - mod : a + b; }

int n, m;

inline bool check(int a, int b, int c)
{	int num = max(a, max(b, c));
	for (register int i = head[num]; ~i; i = nxt[i])
	{	int l = list[i].a;
		int cnt = (l <= a) + (l <= b) + (l <= c);
		if (cnt != list[i].b) return 0;
	}
	return 1;
}

int f[N][N][N];

int Dp()
{	f[0][0][0] = 1;
	int Ans = 0;
	register int i, j, k;
	for (i = 0; i <= n; i++)
	{	for (j = 0; j <= n; j++)
		{	for (k = 0; k <= n; k++)
			{	if (!f[i][j][k]) continue;
				if (!check(i, j, k)) { f[i][j][k] = 0; continue; }
				int p = max(i, max(j, k));
//				if (p == n) { Ans = Plus(Ans, f[i][j][k]); continue; }
				f[p+1][j][k] = Plus(f[p+1][j][k], f[i][j][k]);
				f[i][p+1][k] = Plus(f[i][p+1][k], f[i][j][k]);
				f[i][j][p+1] = Plus(f[i][j][p+1], f[i][j][k]);
			}
		}
	}
	for (int i = 0; i <= n; i++)
		for (int j = 0; j <= n; j++)
		{	Ans = Plus(Ans, f[i][j][n]);
			Ans = Plus(Ans, f[i][n][j]);
			Ans = Plus(Ans, f[n][i][j]);
		}
	return Ans;
}

int main()
{	scanf("%d %d", &n, &m);
	init();
	for (int i = 1; i <= m; i++)
	{	int l, r, x;
		scanf("%d %d %d", &l, &r, &x);
		if (r-l+1 < x) return 0 & puts("0");
		link(r, l, x);
	}
	printf("%d
", Dp());
	return 0;
}
原文地址:https://www.cnblogs.com/2016gdgzoi509/p/9477509.html