zoukankan      html  css  js  c++  java
  • LOJ6089 小Y的背包计数问题(根号优化背包)

    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;
    }
     
  • 相关阅读:
    C# SocketAsyncEventArgs Server
    C# Socket 入门5 UPD 结构体 与 C++ 通信
    如何取得 Func 对象 字段
    动态调用对象的属性和方法——性能和灵活性兼备的方法
    C# 读写锁 ReaderWriteLock
    C# IP多播
    C# 广播通信
    程序员那点儿事
    wince上数据库:sqlce和sqlite
    evc vc字符串转换处理
  • 原文地址:https://www.cnblogs.com/ZH-comld/p/9841123.html
Copyright © 2011-2022 走看看