日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

[CQOI2018] 解锁屏幕(状压dp)

發布時間:2023/12/3 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [CQOI2018] 解锁屏幕(状压dp) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

problem

luogu-P4460

solution

題面以及數據告訴我們顯然是狀壓 dpdpdp

f(s,i):f(s,i):f(s,i): 經過的點集 sss 最后一次畫的點為 iii 的方案數。

直接枚舉下一個之前沒被畫的點 jjj 轉移即可。

f(s∣2j,j)←f(s,i)f(s|2^j,j)\leftarrow f(s,i)f(s2j,j)f(s,i)

但這里需要保證 i,ji,ji,j 兩點間若存在點,必須這些點之前都被畫過了。

我們預處理,開個 bitset\text{bitset}bitsetg(i,j):g(i,j):g(i,j):i,ji,ji,j 貢獻且在 i,ji,ji,j 線段上的點集。

共線判斷我們常用的是斜率,即 yk?yixk?xi=yk?yjxk?xj\frac{y_k-y_i}{x_k-x_i}=\frac{y_k-y_j}{x_k-x_j}xk??xi?yk??yi??=xk??xj?yk??yj??

但計算機 /0/0/0 是會 RE\text{RE}RE 的,所以我們盡量避免處罰,交叉相乘判斷相等即可。

共線只是一個條件,必須是在 i,ji,ji,j 形成的線段上,所以和 i,ji,ji,j 的橫縱坐標判斷一下即可。

最后的最后,就是這道題可以不用完所有點

條件只說了畫的點數不小于 444 即可。

code

#include <bits/stdc++.h> using namespace std; #define int long long #define mod 100000007 #define maxn 20 bitset < maxn > g[maxn][maxn]; int n, ans; int X[maxn], Y[maxn], f[1 << maxn][maxn];bool check( int l, int r, int i ) {if( (X[i] - X[l]) * (Y[i] - Y[r]) != (X[i] - X[r]) * (Y[i] - Y[l]) )return 0;if( (X[i] >= max(X[l], X[r]) or X[i] <= min(X[l], X[r])) and (Y[i] >= max(Y[l], Y[r]) or Y[i] <= min(Y[l], Y[r])) ) return 0;return 1; }signed main() {scanf( "%lld", &n );for( int i = 0;i < n;i ++ ) scanf( "%lld %lld", &X[i], &Y[i] );if( n < 4 ) return ! puts("0");for( int i = 0;i < n;i ++ )for( int j = 0;j < n;j ++ )for( int k = 0;k < n;k ++ )if( i == j or i == k or j == k ) continue;else if( check( i, j, k ) ) g[i][j][k] = 1;for( int i = 0;i < n;i ++ ) f[1 << i][i] = 1;for( int s = 0;s < (1 << n);s ++ ) {for( int i = 0;i < n;i ++ )if( f[s][i] )for( int j = 0;j < n;j ++ )if( s >> j & 1 ) continue;else {for( int k = g[i][j]._Find_first();k != g[i][j].size();k = g[i][j]._Find_next( k ) )if( ! (s >> k & 1) ) goto pass;(f[s | (1 << j)][j] += f[s][i]) %= mod;pass:;}}int ans = 0;for( int s = 0;s < (1 << n);s ++ )if( __builtin_popcount( s ) >= 4 )for( int i = 0;i < n;i ++ )(ans += f[s][i]) %= mod;printf( "%lld\n", ans );return 0; }

總結

以上是生活随笔為你收集整理的[CQOI2018] 解锁屏幕(状压dp)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。