1 条题解
-
0
自动搬运
来自洛谷,原作者为

Siyuan
Dream OIer.搬运于
2025-08-24 21:37:14,当前版本为作者最后更新于2018-12-03 23:34:18,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
题目链接:Luogu 2396
yyy 有 张卡片,每张卡片上都有一个数字 ,每次 yyy 可以选择向前走 步并丢弃第 张卡片。当他手上没有卡片的时候他就赢了;但是有 个“厄运数字”,在“厄运数字”的位置有陷阱,只要 yyy 停在这个格子上他就输了(即使终点是陷阱,那么也输了)。你需要算出 yyy 能赢的方案数,答案对 取模。
数据范围:,
Solution
我们首先可以确定这是一道 题目。由于并没有给出 的具体范围,因此无法把距离设计进状态;又发现每张牌只能用一次并且没有顺序限制,观察到 的范围也很小,我们可以考虑状压 。
我们定义 表示使用了集合 内的卡片有多少种赢的方案。转移时,我们记 表示使用了集合 内的卡片到达的位置,显然当 为“厄运数字”时不能转移。否则我们枚举这次使用的卡片 (),那么有转移方程:$f[i]=\sum_{j=1}^n[j\in i]\cdot f[i\ \texttt{XOR}\ j]$(其中 本质是从集合 中删去元素 )。
时间复杂度:
Code
#include <cstdio> const int N=24; const int mod=1e9+7; int n,m,b1,b2,dis[1<<N],f[1<<N]; void upd(int &x,int y) {(x+=y)>=mod&&(x-=mod);} void solve(int x) { for(int i=x,j;i;i^=j) j=i&-i,upd(f[x],f[x^j]); } int main() { scanf("%d",&n); for(int i=0;i<n;++i) scanf("%d",&dis[1<<i]); scanf("%d",&m); if(m>0) scanf("%d",&b1); if(m>1) scanf("%d",&b2); f[0]=1; int msk=(1<<n)-1; for(int i=1;i<=msk;++i) { int j=i&-i; dis[i]=dis[i^j]+dis[j]; if(dis[i]==b1||dis[i]==b2) continue; solve(i); } printf("%d\n",f[msk]); return 0; }
- 1
信息
- ID
- 1419
- 时间
- 1000ms
- 内存
- 223MiB
- 难度
- 5
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者