NOIP模擬賽 酷子集

2021-08-07 08:53:32 字數 1333 閱讀 1496

題目描述

給出整數n, 則集合s包含整數1, 2, 3, ... , n。考慮s的某個非空子集t,把子集t的所有元素都寫下來,如果使用0-9中每個數字的次數都沒有超過1次(允許是0次),則把子集t稱為酷子集。

例如,子集 和 都是酷子集,而 不是,因為數字4使用了2次。同理,也不是酷子集。

輸入格式

第1行:1個整數n(1≤n≤10^9),表示集合s的元素個數。

輸出格式

第1行:1個整數,表示答案,答案模1e9+7。

輸入樣例 10

輸出樣例

767樣例說明

n=10的所有非空子集有2^10-1=1023個。不是酷子集的情況是同時包含1和10,這類子集一共有2^8 =256個,所以答案是1023-256=767。

題解 by zjx

對於所有滿足條件的集合,每個數字最多出現一次,而總共有10個數字,可以考慮列舉這10個數字的狀態。

設f[s]表示所用的數字集合是s且集合中所有數均不超過n的方案總數。考慮s的乙個子集v,用v組成乙個數,s-v組成其餘的數。

記n有p位:

1.如果|v|2.如果|v|=p,那麼我們一位一位考慮。

①對於某一位k,如果這一位放了乙個小於n這一位的數(當然第一位不能放0),之後的數可以任意排列,方案數為(p-k)!;

②否則我們在這裡放置和原數這一位一樣的數(前提是這些數中有),繼續處理k+1位;

③特別的,如果v完全等於n,答案需要加上1。算出v的方案數後,與f[s-v]相乘即為答案。

3.如果|v|>p,直接賦0。

最後把所有的f[1]~f[2^10-1]加起來就是答案了

#includeconst int mod=1e9+7;

const int n=15;

const int m=(1<<10)+5;

int n, ncnt, note[10];

void prep_digit()

int fac[n], inv[n];

void prep_fi()

for( int i=2; i<=10; i++ ) inv[i]=1ll*inv[i]*inv[i-1]%mod;

}int f[m], bcnt[m], jud, scnt;

void prep_situ() {

scnt=(1<<10);

for( int s=0; s>1]+(s&1);//記錄當前集合包含幾個數

if( bcnt[s]>ncnt ) f[s]=0;//比n的位數多

else if( bcnt[s]

noip模擬賽 密碼

表示沒看懂演算法3 問題描述 有壓迫,就有反抗。mored的寵物在法庭的幫助下終於反抗了。作為乙隻聰明的寵物,他打算把魔法使mored的魔法書盜去,奪取mored的魔法能力。但mored怎麼會讓自己的魔法書輕易地被盜取?mored在魔法書上設定了乙個密碼鎖,密碼鎖上有乙個問題。施以斯臥鋪魔法吧,你有...

NOIP模擬賽 老師

題目描述 一座有n層的教學樓裡有一些學生,第i 0 i n 層有studentsi個學生。你被給定了乙個數k,如果第i層有x個學生,那麼這一層需要 x k 個老師。你可以調整每個學生的樓層,但是每個學生至多只能調整一層,就是說第i層的學生只能去第i 1層 如果有的話 第i層 第i 1層 如果i 1 ...

NOIP模擬賽 分錢

題目描述 兩個人在街上撿到了一些錢,這些錢共有n張,他們等了很久也沒有等來失主,於是決定把錢平分。但錢可能無法平分。他們先把能夠平分的錢盡量先平分了,使得剩下不能平分的錢盡量少。這些不能平分的錢怎麼辦呢他?他們決定拿去賭場裡面賭一把。他們運氣太好了,那些不能平分的錢變成了雙倍,於是他們就把那個錢分了...