zoukankan      html  css  js  c++  java
  • 【题解】HAOI2008木棍分割

      对于这道题目的两问,第一问直接二分答案求出最短长度。关键在于第二问应当如何求:建立dp方程,dp[i][j]代表到第i个分界线,切了j次(强制在第i处切一刀、这样就不会对后面的状态产生影响)。状态转移的方程即是当前分界线枚举上一条分界线在哪里,上一条分界线与当前线之间如果相差不超过之前二分出来的答案,就可以判定合法,方案数累加。因为注意到合法的分界线必然是一段连续区间,且单调右移不减,所以使用一个队列来维护队列内的元素总值。虽然让我感到非常玄学的是明明数据很小,我的数组一开小了就WA?不是很理解……

    #include <bits/stdc++.h>
    using namespace std;
    #define maxn 5000000
    #define maxm 300000
    #define mod 10007
    #define INF 99999999
    int m, maxx, fans, ans, a[maxn], sum[maxn], dp[maxm][3], n, pre = 0, now = 1;
    int q[maxn], tot, head, tail; 
    bool mark[maxn];
    int read()
    {
        int x = 0, k = 1;
        char c;
        c = getchar();
        while(c < '0' || c > '9') { if(c == '-') k = -1; c = getchar(); }
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
        return x * k;
    }
    
    bool check(int x)
    {
        int cnt = m;
        int tem = 0;
        for(int i = 1; i <= n; i ++)
        {
            if(tem + a[i] <= x) tem += a[i];
            else
            {
                if(!cnt) return false;
                tem = a[i], cnt --;
            }
        }
        return true;
    }
    
    void solve()
    {
        int l = maxx, r = sum[n];
        while(l <= r)
        {
            int mid = (l + r) >> 1;
            if(check(mid)) ans = mid, r = mid - 1;
            else l = mid + 1;
        }
    }
    
    void DP()
    {
        dp[0][pre] = 1;
        for(int i = n - 1; i >= 1; i --)
        {
            if(sum[n] - sum[i] <= ans)
                mark[i] = true;
            else break;
        }
        bool flag = false;
        for(int i = 1; i <= m; i ++)
        {
            head = 1, tail = 0;
            q[++ tail] = i - 1, tot = dp[i - 1][pre];
            for(int j = i; j <= n; j ++)
            {
                while(head <= tail && sum[j] - sum[q[head]] > ans) 
                    tot = (tot - dp[q[head]][pre] + mod) % mod, head ++;
                dp[j][now] = tot, dp[j][now] %= mod;
                if(dp[j][pre]) q[++ tail] = j, tot += dp[j][pre], tot %= mod;
                if(mark[j]) 
                {
                    fans += dp[j][now];
                    fans %= mod;
                }
            }
            now ^= 1, pre ^= 1;
        }
    }
    
    int main()
    {
        n = read(), m = read();
        for(int i = 1; i <= n; i ++)
        {
            a[i] = read(), sum[i] = sum[i - 1] + a[i];
            maxx = max(a[i], maxx);
        }    
        solve();
        cout << ans << " ";
        DP();
        cout <<fans << endl;
        return 0;
    }
  • 相关阅读:
    mysql索引
    mysql锁机制
    mysql授权
    mysql执行计划
    mysql知识补遗
    求助:springboot调用存储过程并使用了pagehelper分页时报错com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException
    java面试题1
    Yarn
    MapRudecer
    Hive数据倾斜和解决办法
  • 原文地址:https://www.cnblogs.com/twilight-sx/p/8485260.html
Copyright © 2011-2022 走看看