• [51nod1597]有限背包计数问题


    分块,对于sqrt(n)以内的点用二进制优化多重背包+前缀和来做,处理出f[i][j]表示前i种权值为j的方案数
    对于sqrt(n)以外的点有两个性质:1.与数量无关且数量不超过sqrt(n);2.权值相邻;3.那么一定可以用两种操作来构造出来权值序列:1.加入一个sqrt(n)+1;2.将现有数+1(都不超过n),再用g[i][j]表示选了i个(不是种)权值和为j,可以转移到g[i][i+j]和g[i+1][j+sqrt(n)+1],最后将两个卷起来(题目说恰好为n,所以不用fft)

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define N 100005
     4 #define mod 23333333
     5 int K,n,ans,f[N],sum[N],g[320][N];
     6 int main(){
     7     scanf("%d",&n);
     8     K=(int)sqrt(n);
     9     f[0]=g[0][0]=1;
    10     for(int i=1;i<=K;i++){
    11         for(int j=0;j<i;j++)sum[j]=f[j];
    12         for(int j=i;j<=n;j++)sum[j]=(sum[j-i]+f[j])%mod;
    13         for(int j=0;j<i*i+i;j++)f[j]=sum[j];
    14         for(int j=i*i+i;j<=n;j++)f[j]=(sum[j]-sum[j-i*i-i]+mod)%mod;
    15     }
    16     for(int i=0;i<=K;i++)
    17         for(int j=0;j<=n;j++){
    18             if ((i)&&(i+j<=n))g[i][i+j]=(g[i][i+j]+g[i][j])%mod;
    19             if (j+K<n)g[i+1][j+K+1]=(g[i+1][j+K+1]+g[i][j])%mod;
    20         }
    21     for(int i=1;i<=K;i++)
    22         for(int j=0;j<=n;j++)g[i][j]=(g[i][j]+g[i-1][j])%mod;
    23     for(int i=0;i<=n;i++)ans=(ans+1LL*g[K][i]*f[n-i])%mod;
    24     printf("%d",ans);
    25 }
    View Code
  • 相关阅读:
    关于BFS
    关于bitset
    关于线段树(数组和指针两种实现方法)
    关于RMQ问题
    浅谈树状数组
    洛谷—— P3865 【模板】ST表
    洛谷—— P3807 【模板】卢卡斯定理
    2017-10-29-afternoon-清北模拟赛
    2017-10-29-morning-清北模拟赛
    51Nod 1526 分配 笔名
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/11355851.html
Copyright © 2020-2023  润新知