NOIP模擬 乘積(狀壓DP)

2021-08-09 18:32:20 字數 1523 閱讀 9820

題意:

選擇不超過

k 個

n以內的正整數撐起來,使得乘積是乙個無平方因子數(不能夠被任意乙個質數的平方整除),一共有多少種取法? (n

≤500,k

≤500)

題解:

首先,很容易想到狀壓,壓縮當前已經選過某質數的狀態。對於質數個數小於

20 可以直接過,但是問題是現在

n 以內的質數個數很多,無法壓縮。

考慮狀壓dp的本質:從前往後依次加入數,並更新之前的所有沒有與他共用質因數的狀態。顯然,對於那些質因數分解後只有小質數的數可以直接狀壓dp,現在考慮如何加入其他大的數。

設定乙個分界點n√

來區分大小質因數,乙個數隻可能包含至多乙個大於n√

的質因數,所以每個質數都會而且只會被列舉一次,現在從小(n√

)到大列舉這些質因數:

現在已經列舉到質因數

j ,開始列舉包含

j的每個數aj

,還是將aj

質因數分解,設定乙個te

mp陣列(**中可以不設定,這裡為了方便),因為前面的所有狀態都沒有包含

j ,而且狀壓dp保證了不會重複小質數,可以通過同樣的狀壓dp方式從之前的dp狀態轉移過來。

處理完所有aj

後把tem

p 陣列加入dp

陣列繼續處理j2

即可。

其實這就是個分組揹包而已。

**中先處理了所有不包含

1 的情況,最後對於小於

k的情況乘

2 (選

1和不選

1 ),對於等於

k的情況直接加(不能選

1 ),最後再加上

1即可(只選

1 ).

#include

using

namespace

std;

inline

int read()

while(isdigit(ch))

return i*f;

}const

int lim=(1

<<8)+20,maxn=5e2+50;

const

int prime[8]=;

const

int mod=1e9+7;

int t,n,k,dp[maxn][lim],status[maxn],lim=(1

<<8)-1;

vector

v[maxn];

inline

void pre()

else

if(cnt)status[i]^=(1

if(tmp==1)v[i].push_back(i);

else v[tmp].push_back(i);

}}int main()}}

int ans=0;

for(register

int i=1;i<=k;i++)

}cout

<1

<}

}

NOIP模擬 乘積 狀壓dp 多組揹包

題目大意 選擇不超過k個n以內的正整數相乘,使乘積使乙個無平方因子數,問有多少種取法?每個數只能取一次 1 k,n 500 解題思路 首先可以想到把有平方因子數的數刪了。那問題也就變成了使取得的數的質因數集合無交集。如果質因數個數足夠少,我們就可以狀壓記錄每個質數取還是沒取,但500的範圍太大。不過...

NOI P模擬賽 奶油蛋糕塔(狀壓 DP)

資料範圍1 n 5 1 051 leq n leq5 times10 5 1 n 5 105 n 20 n leq 20 n 20 的狀壓應該都會吧,狀態記錄已經選了的蛋糕集合,以及蛋糕序列的尾部奶油,然後列舉蛋糕轉移。總共有 10 1010 種不同的蛋糕,資料很小。把最後的蛋糕塔等效為乙個序列,如...

校內模擬 記憶(狀壓DP)

考場想到了正解,然後被卡快取記憶體,gg 乙個顯然的轉化就是設e ie i ei 表示朋友選擇第i ii個串的時候的期望操作次數。則答案就是所有e ie i ei 的平均值。首先考慮乙個o n l2l o nl2 l o nl2l 的暴力,對於每個串,列舉所有其他串看有多少個位置相同,則我們能夠知道...