首先這是乙個多重揹包
但是它的資料非常特殊,我們可以利用其性質優化演算法
乙個顯然的優化是
當\(i>\sqrt n\)時,可以取消個數限制
設\(f[i][j]\)表示選了\(i\)個物品,體積為\(j\)的方案數
一共有兩種轉移
可以由\(i-1\)個物品加上乙個最小的物品\(\sqrt n+1\)
可以由\(i\)個物品全部加一(全部換成下乙個)
即\(f[i][j]=f[i-1][j-(\sqrt n+1)]+f[i][j-i]\)
考慮得到乙個答案的過程
對於每乙個過程都會得到乙個合法的答案
對於每乙個合法的答案都有唯一乙個過程
因為對於每乙個方案
如果其中存在最小的物品
那麼一定是由第一種方案轉移
否則一定是由第二種方案轉移
比如\(n=16\)
體積為\(16\)的一種方案是\(5+5+6\)
這個狀態一定由\(5+6\)轉移來
因為\(4=\sqrt 16\),比最小的物品還小
所以\(4+4+5\)是不可能的
體積為\(12\)的一種方案是\(6+6\)
這個狀態一定由\(5+5\)轉移來
因為方案裡並沒有\(5\)(最小的物品)
所以方案與過程一一對應
複雜度\(o(n\sqrt n)\)
剩下的是多重揹包
\(f[i][j]=\sum_^\)
按模\(i\)分類
複雜度\(o(n\sqrt n)\)
最後列舉多少空間給前\(\sqrt n\)個物品(剩下空間給其它物品)
統計答案即可
複雜度\(o(n\sqrt n)\)
#includeusing namespace std;
#define gc c=getchar()
#define r(x) read(x)
templateinline void read(t&x)
while(isdigit(c))x*=k;
}const int p=23333333;
const int n=1e5+7;
int sum[n],f1[2][n],f2[2][n];
inline int add(int a,int b)
int main()
memset(sum,0,i<<2); }
memset(sum,0,(n+1)<<2);
f2[0][0]=1;
for(int i=1;i<=t;++i) }
sum[0]=1;
long long ans=0;
for(int i=0;i<=n;++i)(ans+=1ll*f1[t&1][i]*sum[n-i])%=p;
printf("%lld\n",ans);
}
51nod1597 有限揹包計數問題
你有乙個大小為n的揹包,你有n種物品,第i種物品的大小為i,且有i個,求裝滿這個揹包的方案數有多少 兩種方案不同當且僅當存在至少乙個數i滿足第i種物品使用的數量不同 n 100000,答案模23333333,時限2.333s 這道題一看是一道多重揹包,但是範圍有點大啊。可以嘗試利用一下題目的條件,對...
51nod1597 有限揹包計數問題
51nod1597 有限揹包計數問題 試題描述 你有乙個大小為n的揹包,你有n種物品,第i種物品的大小為i,且有i個,求裝滿這個揹包的方案數有多少 兩種方案不同當且僅當存在至少乙個數i滿足第i種物品使用的數量不同 輸入 第一行乙個正整數n 1 n 10 5 輸出 乙個非負整數表示答案,你需要將答案對...
51nod 1597 有限揹包計數問題 dp
你有乙個大小為n的揹包,你有n種物品,第i種物品的大小為i,且有i個,求裝滿這個揹包的方案數有多少 兩種方案不同當且僅當存在至少乙個數i滿足第i種物品使用的數量不同 1 n 10 5,答案對23333333取模 設lim sqrt n 我們把所有物品按照大於lim和不大於lim分成兩部分。對於大於l...