• BZOJ 2023 [Usaco2005 Nov]Ant Counting 数蚂蚁:dp【前缀和优化】


    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2023

    题意:

      有n个家族,共m只蚂蚁(n <= 1000, m <= 100000)。

      每个家族有cnt[i]只蚂蚁,并且同一家族中的蚂蚁无差别。

      从窝里爬出来x只蚂蚁的方案数为f(x)。

      给定a,b,让你求 ∑ f(a to b) MOD 1000000。

    题解:

      表示状态:

        dp[i][j] = combinations

        i:第i个家族已经考虑过了

        j:目前出来了j只蚂蚁

      找出答案:

        ans = ∑ dp[n][a to b]

      如何转移:

        dp[i][j] = ∑ dp[i-1][j-k] (0 <= k <= cnt[i], j-k >= 0)

        即:dp[i][j] = ∑ dp[i-1][max(0,j-cnt[i]) to j];

     

      边界条件:

        dp[0][0] = 1

        others = 0

      优化:

        (1)裸dp时间复杂度为O(n * m^2) = 10^13,绝对炸了。。。

          所以前缀和优化:求 ∑ dp[i-1][max(0,j-cnt[i]) to j]。

        (2)裸dp空间复杂度为 n*m(Byte) = 95 MB > 64 MB,又炸了咋办。。。

          滚动数组。因为dp[i][j]只会用到dp[i-1][...]。

    AC Code:

     1 // state expression:
     2 // dp[i][j] = combinations
     3 // i: considering ith group
     4 // j: j ants have been outside
     5 //
     6 // find the answer:
     7 // sigma dp[n][a to b]
     8 //
     9 // transferring:
    10 // dp[i][j] = sigma dp[i-1][j-k] (0 <= k <= cnt[i], j-k >= 0)
    11 //
    12 // boundary:
    13 // dp[0][0] = 1
    14 // others = 0
    15 #include <iostream>
    16 #include <stdio.h>
    17 #include <string.h>
    18 #define MAX_N 1005
    19 #define MAX_M 100005
    20 #define MOD 1000000
    21 
    22 using namespace std;
    23 
    24 int n,m,a,b;
    25 int ans=0;
    26 int cnt[MAX_N];
    27 int dp[2][MAX_M];
    28 int sum[2][MAX_M];
    29 
    30 void read()
    31 {
    32     cin>>n>>m>>a>>b;
    33     memset(cnt,0,sizeof(cnt));
    34     int temp;
    35     for(int i=0;i<m;i++)
    36     {
    37         cin>>temp;
    38         cnt[temp]++;
    39     }
    40 }
    41 
    42 int cal_mod(int x)
    43 {
    44     return (x%MOD+MOD)%MOD;
    45 }
    46 
    47 int cal_sum(int k,int x,int y)
    48 {
    49     if(x==0) return cal_mod(sum[k&1][y]);
    50     return cal_mod(sum[k&1][y]-sum[k&1][x-1]);
    51 }
    52 
    53 void update_sum(int k,int x)
    54 {
    55     if(x==0) sum[k&1][x]=cal_mod(dp[k&1][x]);
    56     else sum[k&1][x]=cal_mod(sum[k&1][x-1]+dp[k&1][x]);
    57 }
    58 
    59 void solve()
    60 {
    61     memset(dp,0,sizeof(dp));
    62     dp[0][0]=1;
    63     for(int i=0;i<=m;i++)
    64     {
    65         sum[0][i]=1;
    66     }
    67     for(int i=1;i<=n;i++)
    68     {
    69         for(int j=0;j<=m;j++)
    70         {
    71             dp[i&1][j]=cal_sum(i-1,max(0,j-cnt[i]),j);
    72             update_sum(i,j);
    73         }
    74     }
    75     for(int i=a;i<=b;i++)
    76     {
    77         ans=cal_mod(ans+dp[n&1][i]);
    78     }
    79 }
    80 
    81 void print()
    82 {
    83     cout<<ans<<endl;
    84 }
    85 
    86 int main()
    87 {
    88     read();
    89     solve();
    90     print();
    91 }
  • 相关阅读:
    第八篇、UITableView常用功能(左滑出现多个按钮,多选删除等)
    第七篇、hitTest UITabbar中间突出按钮额外增加可点击区域
    第二篇、常用的分类文件
    第一篇、Swift_Textkit的基本使用
    第六篇、git常用的命令
    第五篇、常用的SQL语句和函数介绍
    第四篇、图片轮播查看器
    C# 打开文件或打开文件夹
    HttpHandler使用Session
    C# Response 下载
  • 原文地址:https://www.cnblogs.com/Leohh/p/7617667.html
Copyright © 2020-2023  润新知