2 条题解
-
1
记忆化搜索题,类似 DP 。
形式化题意:给定 个数,求满足任意两个相邻的数差值大于给定数值的排列方案数。
看到排列一般会直接想到
$$dp[k][state][last]=\sum dp[k+1][state|(1<<(i-1)][i],(state>>(i-1)\text{and}1)==1 $$dfs,但 是 的,dfs会 tle,显然过不了。但不难发现计算时会经常出现前面已经排好的方案不一样,但后面剩下还没排的数都一样的情况,此时就会出现大量重复计算。考虑到影响当前方案数的因素只有:已经排好了多少个、前面都有哪些参与了排列、当前排列的最后一个数是什么。因此记忆化搜索,用 记录当前应该填第 个数,已经填到了 的状态( 在二进制下哪些位上是 就代表哪几个数已经用了)且最后一次填的下标为 的方案数。那么就可以这样转移:关于复杂度:最劣情况下,每一种 被访问一次,对于每一种 ,每一个数字都有机会成为 (如果这个数字在 下),然而 确定了 就确定了。因此 ,而且不容易跑满。
最后不要忘记
dfs的边界条件。 这道题就做完了。
(i-1)][i],(state>#include<bits/stdc++.h> #define int long long using namespace std; inline int re(){ int x=0,f=1; char ch=getchar(); while(!isdigit(ch)){ if(ch=='-')f=-1; ch=getchar(); } while(isdigit(ch)){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } return x*f; } const int N=17; int n,K; int h[N]; int dp[N][(1<<N)][N]; inline int dfs(int k,int state,int last){ if(k==n+1)return 1; if(dp[k][state][last])return dp[k][state][last]; for(int i=1;i<=n;i++){ if((state>>(i-1))&1||abs(h[i]-h[last])<=K)continue; dp[k][state][last]+=dfs(k+1,state|(1<<(i-1)),i); } return dp[k][state][last]; } signed main(){ n=re(),K=re(); for(int i=1;i<=n;i++)h[i]=re(); h[0]=-K-1; cout<<dfs(1,0,0); return 0; }
信息
- ID
- 580
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 5
- 标签
- (无)
- 递交数
- 36
- 已通过
- 15
- 上传者