[CQOI2018]解锁屏幕

解锁屏幕


这图太毒瘤了, 看了几遍看不懂。

直接状压, dp(S,i) 表示走完了集合 S, 停在 i 的方案数。

计算几何水平缺失(

#include <bits/stdc++.h>
using namespace std;

const int mo = 1e8 + 7;

int n;
struct point { int x, y;} p[21]; 
bool is (point a, point b, point c) {
	return (b.y - a.y) * (c.x - b.x) == (b.x - a.x) * (c.y - b.y);
}
int pop_count[1 << 20], nd[21][21];
int dp[1 << 20][20];

int main()
{
	scanf ("%d", & n);
	for (int i = 0; i < n; ++ i)
		scanf ("%d%d", & p[i].x, & p[i].y);
	for (int i = 1; i < (1 << n); ++ i)	
		pop_count[i] = pop_count[i >> 1] + (i & 1);
	for (int i = 0; i < n; ++ i)
		for (int j = 0; j < n; ++ j)
		{
			if (i == j) continue;
			for (int k = 0; k < n; ++ k)
			{
				if (i == k || j == k) continue;
				if (((p[k].x-p[i].x) * (p[k].x-p[j].x)<0||(p[k].y-p[i].y) * (p[k].y-p[j].y)<0) && is (p[i], p[k], p[j])) nd[i][j] |= 1 << k;
			}
		}
	long long ans = 0ll;
	for (int i = 0; i < n; ++ i)
		dp[1 << i][i] = 1;
	for (int i = 1; i < (1 << n); ++ i)
	{
		for (int j = 0; j < n; ++ j)
			if (dp[i][j] && ((i>>j) & 1))
			{
				if (pop_count[i] >= 4) ans += dp[i][j], ans %= mo;
				for (int k = 0; k < n; ++ k)
					if (((i>>k) & 1) == 0 && (nd[j][k] & i) == nd[j][k])
						dp[i | (1 << k)][k] += dp[i][j], dp[i | (1 << k)][k] %= mo;
			}
	}
	cout << ans;
	return 0;
}
posted @ 2021-03-03 17:26  xwmwr  阅读(55)  评论(0编辑  收藏  举报