bzoj1072 scoi2007 排列(狀壓dp

2021-09-27 01:25:14 字數 1461 閱讀 6639

給乙個數字串s和正整數d, 統計s有多少種不同的排列能被d整除(可以有前導0)。例如123434有90種排列能

被2整除,其中末位為2的有30種,末位為4的有60種。

input

輸入第一行是乙個整數t,表示測試資料的個數,以下每行一組s和d,中間用空格隔開。s保證只包含數字0, 1

, 2, 3, 4, 5, 6, 7, 8, 9.

output

每個資料僅一行,表示能被d整除的排列的個數。

sample input

000 1

001 1

1234567890 1

123434 2

1234 7

12345 17

12345678 29

sample output

hint

在前三個例子中,排列分別有1, 3, 3628800種,它們都是1的倍數。

【限制】

100%的資料滿足:s的長度不超過10, 1<=d<=1000, 1<=t<=15

有資料範圍可知,複雜度大約是o(2

n∗d∗

t)

o(2^n*d*t)

o(2n∗d

∗t)(別奇怪我真這麼看出來的= =,坑爹的是還要乘個 n

nn我們先假設各個元素不相同,最後再除掉階乘即可

這種整除的問題,一般都要開一維表示餘數,這樣才能轉移

於是我們令 f[s

][k]

f[s][k]

f[s][k

] 表示當前已選集合為 s

ss ,膜 d

dd 為 k

kk 的排列數。

考慮轉移。我們需要選定乙個元素 i

ii 作為最後加入 s

ss 的數。轉移方程:

f [s

∣(

1<

][(j

∗10+a

[i])

modd

]+=f

[s][

j]

f[s|(1s∣(1

<

][(j

∗10+

a[i]

)mod

d]+=

f[s]

[j]

#include #define n 10

#define ll long long

using namespace std;

ll f[1

int a[15], cnt[15];

int main()

for(i = 0; i < (1 << n); i++)

}} ans = f[(1 << n) - 1][0];

for(i = 0; i < 10; i++)

printf("%d\n", ans);

} return 0;

}

BZOJ 1079 SCOI2008 著色方案

題目 分析 一看就覺得是dp或者直接排列組合公式或者容斥?我就只想到dp的,我們用dp i j 表示前i種顏色,排列出有j對相鄰一樣顏色的方案數。當出現乙個新的顏色時,我們把這個顏色插板法插進去,我們要列舉插入的方式,可能插到相鄰顏色一樣的中間,或者不是,然後進行狀態轉移.具體看 include i...

BZOJ1066 SCOI2007蜥蜴 最大流

挺顯然的最大流,源向所有有蜥蜴的點連inf邊,所有點拆成入點和出點,入店向出點連流量為高度的邊,限制流量,所有可以一步跳出去的點向匯連inf邊,跑最大流就行了。include include include define inf 99999999 define maxn 1005 using nam...

BZOJ1079 SCOI2008著色方案 DP

只能想到 5 15 的方法。我們要利用起 ci比較小這個性質,f a b c d e last 表示有a 種顏色用了1個,b種顏色用了2個 上一次染色用的是剩餘 last 個的顏色,轉移就是f a,b,c,d,e,last a last 2 f a 1,b,c,d,e b last 3 f a 1,...