洛谷P2396 yyy loves Maths VII
P2396 yyy loves Maths VII
题目背景
yyy对某些数字有着情有独钟的喜爱,他叫他们为幸运数字;然而他作死太多,所以把自己讨厌的数字成为"厄运数字"
题目描述
一群同学在和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
输入输出样例
说明
数据范围:
10%的数据n<=10
50%的数据n<=23
100%的数据n<=24
sol:这样的数据范围,感觉不是爆搜,状压dp无疑
dp[z]表示状态为z时没有厄运数字的方案数
转移较易:枚举一个在集合z中的数字i,dp[z]+=dp[z^i]
注意判断Dis,即一个集合z的距离和Dis[z]为厄运数字,那么不能进行转移
要用lowbit进行帮助转移
lowbit(x)表示一个数在二进制意义下第一位非0的数位 可以帮助枚举一个集合,比(1~n)要快
register帮助卡常
#include <bits/stdc++.h> using namespace std; typedef int ll; inline ll read() { ll s=0; bool f=0; char ch=' '; while(!isdigit(ch)) { f|=(ch=='-'); ch=getchar(); } while(isdigit(ch)) { s=(s<<3)+(s<<1)+(ch^48); ch=getchar(); } return (f)?(-s):(s); } #define R(x) x=read() inline void write(ll x) { if(x<0) { putchar('-'); x=-x; } if(x<10) { putchar(x+'0'); return; } write(x/10); putchar((x%10)+'0'); return; } #define W(x) write(x),putchar(' ') #define Wl(x) write(x),putchar('\n') const int N=(1<<24)+5,Mod=1000000007; int n,m,B1,B2,Dis[N],dp[N]; #define lowbit(x) ((x)&(-x)) int main() { register int i,j; R(n); for(i=1;i<=n;i++) R(Dis[1<<(i-1)]); R(m); if(m>0) R(B1); if(m>1) R(B2); dp[0]=1; for(i=1;i<(1<<n);i++) { Dis[i]=Dis[i^(lowbit(i))]+Dis[lowbit(i)]; if(Dis[i]==B1||Dis[i]==B2) continue; for(j=i;j;j^=lowbit(j)) { dp[i]+=dp[i^lowbit(j)]; dp[i]-=(dp[i]>=Mod)?Mod:0; } } Wl(dp[(1<<n)-1]); return 0; } /* input 8 1 3 1 5 2 2 2 3 0 output 40320 input 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 output 0 */