题目描述
一群同学在和yyy玩一个游戏
每次,他们会给yyy n张卡片,卡片上有数字,所有的数字都是"幸运数字",我们认为第i张卡片上数字是ai
每次yyy可以选择向前走ai步并且丢掉第i张卡片
当他手上没有卡片的时候他就赢了
但是呢,大家对"厄运数字"的位置布置下了陷阱,如果yyy停在这个格子上,那么他就输了
(注意:即使到了终点,但是这个位置是厄运数字,那么也输了)
现在,有些同学开始问:
yyy有多大的概率会赢呢?
大家觉得这是个好问题
有人立即让yyy写个程序
“电脑运行速度很快!24的阶乘也不过就620448401733239439360000,yyy你快写个程序来算一算”
yyy表示很无语,他表示他不想算概率,最多算算赢的方案数,而且是%1,000,000,007以后的值
大家都不会写程序,只好妥协
但是这时候yyy为难了,24!太大了,要跑好长时间.
他时间严重不够!需要你的帮助!
由于yyy人格分裂,某个数字可能既属于幸运数字又属于厄运数字。
输入格式
第一行n
下面一行n张卡片
第三行m 表示yyy的厄运数字个数(最多2个)
最后一行是m个厄运数字
输出格式
方案数%1,000,000,007
输入输出样例
输入 #1复制
8
1 3 1 5 2 2 2 3
0
输出 #1复制
40320
输入 #2复制
24
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
2
10 15
输出 #2复制
0
说明/提示
数据范围:
10%的数据n<=10
50%的数据n<=23
100%的数据n<=24
听说这道题比较卡常,但是为什么我最高才300ms。。。。。。
看到n只有24,明显的爆搜,可能我剪枝有问题,然后TLE。。。。最后直接状压DP了。
我们存一下当前状态的个数,当前状态的距离即可。
对于每个状态,我们需要提取每个1出来,直接lowbit就好了,不然复杂度是很卡的。
AC代码:
#pragma GCC optimize("-Ofast","-funroll-all-loops")
#include<bits/stdc++.h>
//#define int long long
#define lowbit(x) (x&(-x))
using namespace std;
const int mod=1e9+7;
int n,m,e[2],dp[1<<24],d[1<<24];
signed main(){
cin>>n;
for(int i=0;i<n;i++) cin>>d[1<<i];
cin>>m;
for(int i=0;i<m;i++) cin>>e[i];
dp[0]=1;
for(int i=1;i<(1<<n);i++){
d[i]=d[i^lowbit(i)]+d[lowbit(i)];
if(d[i]==e[0]||d[i]==e[1]) continue;
for(int j=i,k;j;j^=k){
k=lowbit(j); dp[i]+=dp[i^k]; if(dp[i]>=mod) dp[i]-=mod;
}
}
cout<<dp[(1<<n)-1];
return 0;
}