1. 程式人生 > >[CQOI 2018]解鎖屏幕

[CQOI 2018]解鎖屏幕

AI print \n 預處理 spa mat esp != urn

Description

題庫鏈接

給出平面上 \(n\) 個點,一開始你可以選任何一個點作為起點,接著對於每一個你在的位置,你可以選取一個未走過的點。將路徑(線段)上所有的點均選上(包括起點終點),並走到選擇的那個點上。詢問選的點的個數 \(\geq 4\) 的方案數。區別不同的方案,只需要路徑不一樣即可。

\(1\leq n\leq 20\)

Solution

狀壓 \(dp\)

先預處理出兩點間路徑上會經過的點。 \(dp\) 的時候需要選擇路徑上不會經過未選擇點的方案走。

復雜度 \(O(n^3+2^nn^2)\)

Code

#include <bits/stdc++.h>
#define lowbit(x) ((x)&(-(x))) using namespace std; const int N = 20+5, SIZE = (1<<20)+5, yzh = 100000007; struct point { int x, y; point (int _x = 0, int _y = 0) {x = _x, y = _y; } point operator - (const point &b) const {return point(x-b.x, y-b.y); } int operator * (const point &b) const
{return x*b.y-y*b.x; } }a[N]; int n, mp[N][N], bin[N], f[SIZE][N], cnt[SIZE], ans; void check(int x, int y) { int mxx = max(a[x].x, a[y].x), mnx = min(a[x].x, a[y].x); int mxy = max(a[x].y, a[y].y), mny = min(a[x].y, a[y].y); for (int i = 1; i <= n; i++) if (i != x && i != y) if
((a[y]-a[x])*(a[i]-a[x]) == 0) if (a[i].x >= mnx && a[i].x <= mxx && a[i].y >= mny && a[i].y <= mxy) mp[x][y] |= bin[i-1]; } void work() { scanf("%d", &n); bin[0] = 1; for (int i = 1; i <= n; i++) bin[i] = bin[i-1]<<1; for (int i = 1; i <= bin[n]; i++) cnt[i] = cnt[i-lowbit(i)]+1; for (int i = 1; i <= n; i++) scanf("%d%d", &a[i].x, &a[i].y); for (int i = 1; i <= n; i++) for (int j = i+1; j <= n; j++) check(i, j); f[0][0] = 1; for (int i = 0; i < bin[n]; i++) for (int j = 0; j <= n; j++) if (f[i][j]) for (int k = 1; k <= n; k++) if (!(bin[k-1]&i)) { int x = j, y = k; if (x > y) swap(x, y); if ((i&mp[x][y]) == mp[x][y]) (f[i|bin[k-1]][k] += f[i][j]) %= yzh; } for (int i = 0; i < bin[n]; i++) if (cnt[i] >= 4) for (int j = 1; j <= n; j++) (ans += f[i][j]) %= yzh; printf("%d\n", ans); } int main() {work(); return 0; }

[CQOI 2018]解鎖屏幕