[Luogu P2396] yyy loves Maths VII
阿新 • • 發佈:2018-12-17
洛谷傳送門
題目背景
yyy對某些數字有著情有獨鍾的喜愛,他叫他們為幸運數字;然而他作死太多,所以把自己討厭的數字成為"厄運數字"
題目描述
一群同學在和yyy玩一個遊戲
每次,他們會給yyy 張卡片,卡片上有數字,所有的數字都是"幸運數字",我們認為第張卡片上數字是
每次yyy可以選擇向前走步並且丟掉第張卡片
當他手上沒有卡片的時候他就贏了
但是呢,大家對"厄運數字"的位置佈置下了陷阱,如果yyy停在這個格子上,那麼他就輸了
(注意:即使到了終點,但是這個位置是厄運數字,那麼也輸了)
現在,有些同學開始問:
yyy有多大的概率會贏呢?
大家覺得這是個好問題
有人立即讓yyy寫個程式
“電腦執行速度很快!的階乘也不過就,yyy你快寫個程式來算一算”
yyy表示很無語,他表示他不想算概率,最多算算贏的方案數,而且是以後的值
大家都不會寫程式,只好妥協
但是這時候yyy為難了,太大了,要跑好長時間.
他時間嚴重不夠!需要你的幫助!
由於yyy人格分裂,某個數字可能既屬於幸運數字又屬於厄運數字。
輸入輸出格式
輸入格式:
第一行
下面一行張卡片
第三行 表示yyy的厄運數字個數(最多個)
最後一行是個厄運數字
輸出格式:
方案數
輸入輸出樣例
輸入樣例#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
說明
資料範圍:
的資料
的資料
的資料
解題分析
卡常大狀壓…
因為, 直接考慮列舉每種選擇的狀態暴力轉移。 不過有個小技巧: 轉移某個狀態的時候直接用計算前一個可以轉移的位置, 這樣做會列舉次, 就可以卡過去了…
程式碼如下:
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cctype>
#include <cmath>
#include <algorithm>
#define R register
#define IN inline
#define W while
#define MOD 1000000007u
#define uint unsigned int
#define lbt(i) ((i) & (-(i)))
IN void add(uint &a, R int ad) {a += ad; if(a >= MOD) a -= MOD;}
uint dp[1 << 24], dis[1 << 24], bad[2], to[24];
int tot, bcnt;
int main(void)
{
R int i, j, k, bd;
scanf("%d", &tot); bd = (1 << tot) - 1;
for (i = 0; i < tot; ++i) scanf("%d", &to[i]);
scanf("%d", &bcnt); bad[0] = bad[1] = -1;
for (i = 0; i < bcnt; ++i) scanf("%d", &bad[i]);
dp[0] = 1;
for (i = 1; i <= bd; ++i)
{
j = __builtin_ctz(i);
dis[i] = dis[i - (1 << j)] + to[j];
if(dis[i] == bad[0] || dis[i] == bad[1]) continue;
j = i;
W (j) k = lbt(j), add(dp[i], dp[i ^ k]), j ^= k;
}
printf("%u", dp[bd]);
}