1. 程式人生 > >LOJ6089 小Y的背包計數問題(根號優化背包)

LOJ6089 小Y的背包計數問題(根號優化背包)

技術 ret font mage inf 方案 分享圖片 clu 利用

技術分享圖片

Solutioon

這道題利用根號分治可以把復雜度降到n根號n級別。

我們發現當物品體積大與根號n時,就是一個完全背包,換句話說就是沒有了個數限制。

進一步我們發現,這個背包最多只能放根號n個物品。

所以我們設dp[i][j]表示放了i個物品,體積為j時的方案數。

轉移的話一種是往背包裏放一個新物品,或者讓背包裏所有物品體積加1.

當物品體積小於根號n時,因為物品個數比較少,所以我們可以設計狀態為dp[i][j]表示前i個物品,占用j的體積為j時的方案數。

然後我們發現它的同類轉移點是在模i的剩余系下是相等的,所以我們按照余數分組dp一下。

code

#include<iostream>
#include
<cstdio> #include<cmath> #define N 100002 using namespace std; typedef long long ll; const int mod=23333333; int f[317][N],g[317][N],s[N],sum[N],ji[N],ans; int n,n1; int main(){ scanf("%d",&n);n1=sqrt(n); for(int i=1;i<=n1;++i) g[0][0]=1;s[0]=1; for(int i=1;i<=n1;++i)
for(int j=0;j<=n;++j){ if(j>=i)(g[i][j]+=g[i][j-i])%=mod; if(j>=n1+1)(g[i][j]+=g[i-1][j-n1-1])%=mod; (s[j]+=g[i][j])%=mod; } f[0][0]=1; for(int i=1;i<=n1;++i) for(int j=0;j<i;++j){ int tot=0; for(int k=j;k<=n;k+=i){ ji[
++tot]=f[i-1][k]; sum[tot]=(sum[tot-1]+ji[tot])%mod; (f[i][k]+=(sum[tot]-sum[max(0,tot-i-1)]+mod))%=mod; } } for(int i=0;i<=n;++i)(ans+=1ll*s[i]*f[n1][n-i]%mod)%=mod; cout<<ans; return 0; }

LOJ6089 小Y的背包計數問題(根號優化背包)