[BZOJ 2734] 集合选数
生活随笔
收集整理的這篇文章主要介紹了
[BZOJ 2734] 集合选数
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
Link:
BZOJ 2734 傳送門
Solution:
真是奧妙重重的建模啊.....
我們發現$x,2*x,3*x$這些數太分散了,難以處理
于是我們構建這樣的表格:
?
x ?3x ?9x ?27x....
2x ?6x ?18x ?54x...
4x ?12x ? 36x ?108x...
...? ?.....? ? .....? ? ......
?
將問題轉化為求表格上任意兩點不相鄰的點集數。
由于$2^{17}>100000$,因此直接對每一行的信息狀壓就行了
設$dp[i][j]$為到第$i$行且其狀態為$j$時的方案總數,上一層狀態為$k$,判斷!(k&j) && !(j&(j>>1))即可
?
Note:由于一個表格不能包含所有數,因此要建多個表格,結果相乘
Code:
//by NewErA #include <bits/stdc++.h>using namespace std; typedef long long ll; const int MOD=1e9+1;const int MAXN=100005; ll n,dp[50][MAXN],dat[50][50],len[50],last; bool vis[MAXN];ll cal(int x) {dat[1][1]=x;for(int i=1;;i++){if(i>1) dat[i][1]=dat[i-1][1]*2;if(dat[i][1]>n){last=i-1;break;}vis[dat[i][1]]=true;for(int j=2;;j++){dat[i][j]=dat[i][j-1]*3;if(dat[i][j]>n){len[i]=j-1;break;}vis[dat[i][j]]=true;}}for(int i=0;i<=last+1;i++)for(int j=0;j<=(1<<len[i]);j++) dp[i][j]=0;dp[0][0]=1;len[0]=1; //狀壓DPfor(int i=0;i<=last;i++)for(int j=0;j<(1<<len[i]);j++)if(dp[i][j])for(int k=0;k<(1<<len[i+1]);k++)if(!(j&k) && !(k&(k>>1))) dp[i+1][k]=(dp[i+1][k]+dp[i][j])%MOD;return dp[last+1][0]; }int main() {cin >> n;ll res=1;for(int i=1;i<=n;i++)if(!vis[i]) res=res*cal(i)%MOD;cout << res;return 0; }?
Review:
1、當信息較為分散時,通過構建矩陣等各類方式將相關條件集中處理
?
2、求矩陣中任意兩點不相鄰的點集數(經典問題)
狀壓DP的應用,整體$!(j&k)$和$!k&(k>>1)$判斷的方式還行
?
轉載于:https://www.cnblogs.com/newera/p/9141390.html
總結
以上是生活随笔為你收集整理的[BZOJ 2734] 集合选数的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 小程序 判断
- 下一篇: 特征值分解与奇异值分解的相关学习记录