zoukankan      html  css  js  c++  java
  • bzoj 1044 [HAOI2008]木棍分割(二分+贪心,DP+优化)

    【题目链接】

        http://www.lydsy.com/JudgeOnline/problem.php?id=1044

    【题意】

        n根木棍拼到一起,最多可以切m刀,问切成后最大段的最小值及其方案数。

    【思路】

        对于第一问可以二分后贪心判断。

        假设第一问得到的答案为L,设f[i][j]前i个木棍切j下且保持段长不超过L的方案数,则有转移式:

            f[i][j]=sigma { f[k][j-1] },k<i,suma(k+1,i)<=L

        优化:

        空间方面可以用个滚动数组。

            时间方面由于前缀和sum是递增的,所以我们拿个指针qf维护一个滑动窗口,使得窗口满足suma<=L,tot顺便记一下和就出来了。

    【代码】

     1 #include<set>
     2 #include<cmath>
     3 #include<queue>
     4 #include<vector>
     5 #include<cstdio>
     6 #include<cstring>
     7 #include<iostream>
     8 #include<algorithm>
     9 #define trav(u,i) for(int i=front[u];i;i=e[i].nxt)
    10 #define FOR(a,b,c) for(int a=(b);a<=(c);a++)
    11 #define rep(a,b,c) for(int a=(b);a>=(c);a--)
    12 using namespace std;
    13 
    14 typedef long long ll;
    15 const int N = 1e5+10;
    16 const int mod = 1e4+7;
    17 
    18 ll read() {
    19     char c=getchar();
    20     ll f=1,x=0;
    21     while(!isdigit(c)) {
    22         if(c=='-') f=-1; c=getchar();
    23     }
    24     while(isdigit(c))
    25         x=x*10+c-'0',c=getchar();
    26     return x*f;
    27 }
    28 
    29 int n,m,ans,a[N],sum[N],f[2][N],cur,q[N],qf,qr;
    30 
    31 bool can(int M)
    32 {
    33     int cnt=0,tot=0;
    34     FOR(i,1,n) {
    35         if(tot+a[i]>M) {
    36             if((++cnt)>m) return 0;
    37             tot=0;
    38         }
    39         tot+=a[i];
    40     }
    41     return 1;
    42 }
    43 
    44 int main()
    45 {
    46 //    freopen("in.in","r",stdin);
    47 //    freopen("out.out","w",stdout);
    48     n=read(),m=read();
    49     int L=0,R=0;
    50     FOR(i,1,n)
    51     {
    52         a[i]=read(),
    53         sum[i]=sum[i-1]+a[i];
    54         L=max(L,a[i]);
    55     }
    56     R=sum[n];
    57     while(L<R)
    58     {
    59         int M=L+R>>1;
    60         if(can(M)) R=M; else L=M+1;
    61     }
    62     printf("%d ",L);
    63 
    64     FOR(j,0,m)
    65     {
    66         cur^=1;
    67         int tot=0,qf=1;
    68         FOR(i,1,n)
    69         {
    70             if(!j) f[cur][i]=sum[i]<=L;
    71             else {
    72                 while(qf<i && sum[i]-sum[qf]>L)
    73                     tot=(tot-f[cur^1][qf++]+mod)%mod;
    74                 f[cur][i]=tot;
    75             }
    76             tot=(tot+f[cur^1][i])%mod;
    77         }
    78         ans=(ans+f[cur][n])%mod;
    79     }
    80     printf("%d
    ",ans);
    81     return 0;
    82 }
  • 相关阅读:
    分层图最短路(DP思想) BZOJ2662 [BeiJing wc2012]冻结
    动态规划 BZOJ1925 地精部落
    线性DP SPOJ Mobile Service
    线性DP codevs2185 最长公共上升子序列
    数位DP POJ3208 Apocalypse Someday
    线性DP POJ3666 Making the Grade
    杨氏矩阵 线性DP? POJ2279 Mr.Young's Picture Permutations
    tarjan强连通分量 洛谷P1262 间谍网络
    树链剖分 BZOJ3589 动态树
    二分图 BZOJ4554 [Tjoi2016&Heoi2016]游戏
  • 原文地址:https://www.cnblogs.com/lidaxin/p/5350151.html
Copyright © 2011-2022 走看看