• 题解 51nod 1597 有限背包计数问题


    题目传送门

    题目大意

    给出 (n),第 (i) 个数有 (i) 个,问凑出 (n) 的方案数。

    (nle 10^5)

    思路

    呜呜呜,傻掉了。。。

    首先想到根号分治,分别考虑 ([1,sqrt n]) 以及 ([sqrt n+1,n])

    1. ([1,sqrt n])

    不难看出这部分可以直接 dp,设 (f_{i,j}) 为前面 (i) 种物品选出重量为 (j) 的方案数,可以得到转移式:

    [f_{i,j}=f_{i-1,j}+f_{i,j-i}-f_{i-1,j-i imes (i+1)} ]

    1. ([sqrt n+1,n])

    不难看出这部分最多选出 (sqrt n) 个物品,于是可以设 (g_{i,j}) 表示选了 (i) 物品,选出重量为 (j) 的方案数。可以得到转移式:

    [g_{i,j}=g_{i,j-i}+g_{i,j-sqrt n-1} ]

    具体含义就是转移有两种,第一种就是集体右移,即重量为 (k) 的都变为 (k+1),另外一种就是选 (sqrt n+1)


    综上时空复杂度 (Theta(nlog n)),第一种记得滚动数组,不然会 MLE。

    ( exttt{Code})

    #include <bits/stdc++.h>
    using namespace std;
    
    #define Int register int
    #define mod 23333333 
    #define MAXN 100005
    #define MAXM 325
    
    template <typename T> void read (T &x){char c = getchar ();x = 0;int f = 1;while (c < '0' || c > '9') f = (c == '-' ? -1 : 1),c = getchar ();while (c >= '0' && c <= '9') x = x * 10 + c - '0',c = getchar ();x *= f;}
    template <typename T,typename ... Args> void read (T &x,Args& ... args){read (x),read (args...);}
    template <typename T> void write (T x){if (x < 0) x = -x,putchar ('-');if (x > 9) write (x / 10);putchar (x % 10 + '0');}
    
    int n,sqr;
    int f[2][MAXN],g[MAXM][MAXN],f1[MAXN],f2[MAXN];
    /*
    f[i][j] 表示前面i个物品选出重量j的方案数,g[i][j]表示i个物品选出重量j的方案数 
    f[i][j]=f[i-1][j]+f[i][j-i]-f[i-1][j-i*(i+1)]
    g[i][j]=g[i][j-i]+g[i-1][j-sqr-1]
    */
    
    int dec (int a,int b){return a >= b ? a - b : a + mod - b;}
    int add (int a,int b){return a + b >= mod ? a + b - mod : a + b;}
    
    void Work1 (){
    	f[0][0] = 1;
    	for (Int i = 1;i <= sqr;++ i)
    		for (Int j = 0;j <= n;++ j)
    			f[i & 1][j] = add (f[i - 1 & 1][j],dec (j >= i ? f[i & 1][j - i] : 0,j >= i * (i + 1) ? f[i - 1 & 1][j - i * (i + 1)] : 0));
    	for (Int i = 0;i <= n;++ i) f1[i] = f[sqr & 1][i];
    }
    
    void Work2 (){
    	g[0][0] = 1;
    	for (Int i = 1;i <= sqr;++ i)
    		for (Int j = 0;j <= n;++ j)
    			g[i][j] = add (j >= i ? g[i][j - i] : 0,j >= sqr + 1 ? g[i - 1][j - sqr - 1] : 0); 
    	for (Int i = 0;i <= n;++ i)
    		for (Int j = 0;j <= sqr;++ j) f2[i] = add (f2[i],g[j][i]);
    }
    
    signed main(){
    	read (n),sqr = sqrt (n),Work1(),Work2 ();
    	int ans = 0;for (Int i = 0;i <= n;++ i) ans = add (ans,1ll * f1[i] * f2[n - i] % mod);
    	write (ans),putchar ('
    ');
    	return 0;
    }
    
  • 相关阅读:
    P3386 【模板】二分图最大匹配 题解(匈牙利算法)
    B. Repetitions Decoding 题解(思维+构造)
    D. Big Brush 题解(构造+bfs)
    软件使用 蓝湖的基础使用
    破解版navicate数据库 15版本
    大腕web2.0版
    JPA(JPQL)批量操作的示例及真实执行逻辑
    Java线程池的使用示例及注意事项
    解决docker开启端口映射后,会直接穿透本机防火墙的问题
    PostgreSQL用户访问多个schema及其他常用命令
  • 原文地址:https://www.cnblogs.com/Dark-Romance/p/14012628.html
Copyright © 2020-2023  润新知