bzoj 3612: [Heoi2014]平衡【整数划分dp】

其实就是-n~n中求选k个不同的数,和为0的方案数

学到了新姿势叫整数划分,具体实现是dp 详见:https://blog.csdn.net/Vmurder/article/details/42551603

设f[i][j]为j个数和为i的方案数,然后因为互不相同,所以转移的话有两种,就是当前j个数全部+1,和当前j个数全部+1并且多填一个1出来,也就是f[i][j]=f[i-j][j]+f[i-j][j-1]

但是这里要求选的数不能超过n,我们考虑i>n的f中一定有一个大于n的数,我们把这种情况减掉就行了,也就是f[i][j]-=f[i-n-1][j-1]

这是上面那个blog的截图

#include<iostream>
#include<cstdio>
using namespace std;
const int N=100005;
int T,n,m,mod,f[N][15],ans;
int read()
{
    int r=0,f=1;
    char p=getchar();
    while(p>‘9‘||p<‘0‘)
    {
        if(p==‘-‘)
            f=-1;
        p=getchar();
    }
    while(p>=‘0‘&&p<=‘9‘)
    {
        r=r*10+p-48;
        p=getchar();
    }
    return r*f;
}
int main()
{
    T=read();
    while(T--)
    {
        n=read(),m=read(),mod=read();
        f[0][0]=1,ans=0;
        for(int i=1;i<=n*m;i++)
            for(int j=1;j<=m;j++)
            {
                if(i>=j)
                    f[i][j]=(f[i-j][j]+f[i-j][j-1])%mod;
                if(i>n)
                    f[i][j]=(f[i][j]-f[i-n-1][j-1]+mod)%mod;
            }
        for(int i=1;i<=n*m;i++)
            for(int j=1;j<=m;j++)
            {
                ans=(ans+f[i][j]*f[i][m-j])%mod;
                if(j!=m)
                    ans=(ans+f[i][j]*f[i][m-j-1])%mod;
            }
        printf("%d\n",ans+(m==1));
    }
    return 0;
}

原文地址:https://www.cnblogs.com/lokiii/p/9641547.html

时间: 2024-10-14 06:19:51

bzoj 3612: [Heoi2014]平衡【整数划分dp】的相关文章

BZOJ 3612: [Heoi2014]平衡( dp )

枚举Fl, 就变成一个整数划分的问题了...f(i,j) = f(i-j,j-1)+f(i-j,j)-f(i-N-1,j-1)递推.f(i,j)表示数i由j个不同的数组成,且最大不超过N的方案数 -------------------------------------------------------------------------- #include<cstdio> #include<cstring> #include<algorithm> using nam

【BZOJ3612】【HEOI2014】平衡 整数划分、

题意: 有一个杠杆,半长为n,在(2n+1)个整数坐标各有一个质量相同的砝码. 现在给出n,然后再给出要取走的砝码个数,问使得最终杠杆依然平衡的最终方案数是多少. (文末会给出原题帽) 分析: 数据范围不大,我们可以写整数划分. f[i][j]表示将i划分成j个互不相同的正整数,且最大不超过n 的划分方案数. 这里说一下这道题的整数划分. 我们不妨先来反向思考一下.------------------------------------------------------------------

整数划分dp

整数划分 --- 一个老生长谈的问题: 1) 练练组合数学能力. 2) 练练递归思想 3) 练练DP 总之是一道经典的不能再经典的题目: 这道好题求: 1. 将n划分成若干正整数之和的划分数. 2. 将n划分成k个正整数之和的划分数. 3. 将n划分成最大数不超过k的划分数. 4. 将n划分成若干奇正整数之和的划分数. 5. 将n划分成若干不同整数之和的划分数. 1.将n划分成不大于m的划分法: 1).若是划分多个整数可以存在相同的: dp[n][m]= dp[n][m-1]+ dp[n-m][

hdu 5230 整数划分 dp

题目:http://acm.hdu.edu.cn/showproblem.php?pid=5230 题意:给定n,c,l,r.求有多少种方法从1~n-1选取任意k数每个数的权重为其下标,使得这些数字之和加上c之后在l,r范围内. 题解:第一反应是计数01包,但是范围给定的n太大,TLE... 然后仔细想想,不就是求l~r范围内不重复的整数划分数嘛. dp[i][j]表示j这个数字,当前的拆分拥有i个拆分数时的方案数. 先考虑允许重复数字 : dp[i][j] = dp[i][j - i] + d

51nod 1201 整数划分(dp)

题目链接:https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1201 题解:显然是一道dp,不妨设dp[i][j]表示数字i分成j个一共有几种分法. 那么转移方程式为: dp[i][j] = dp[i - 1][j] + dp[i - 1][j - 1] 表示将i - 1划分为j个数,然后j个数都+1 还是不重复,将i - 1划分为j - 1个数,然后j - 1个数都+1,再加上1这个数. 然后就是j的范围要知道1+2+

BZOJ 1263 SCOI 2006 整数划分 高精度

题目大意:给出一个整数,问吧这个整数分成任意多个正整数只和的最大乘积是多少. 思路:根据小学奥数的基本知识,我们要吧这个数字分成尽量多个3.然后这个题就解决了. CODE: #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; struct BigInt{ int num[10010],len; BigInt(int

整数划分 (区间DP)

整数划分(四) 时间限制:1000 ms  |  内存限制:65535 KB 难度:3 描述 暑假来了,hrdv 又要留学校在参加ACM集训了,集训的生活非常Happy(ps:你懂得),可是他最近遇到了一个难题,让他百思不得其解,他非常郁闷..亲爱的你能帮帮他吗? 问题是我们经常见到的整数划分,给出两个整数 n , m ,要求在 n 中加入m - 1 个乘号,将n分成m段,求出这m段的最大乘积 输入 第一行是一个整数T,表示有T组测试数据接下来T行,每行有两个正整数 n,m ( 1<= n <

BZOJ 1263: [SCOI2006]整数划分( 高精度 )

yy一下发现好像越小越好...分解成3*3*3*3……这种形式是最好的...然后就是高精度了 --------------------------------------------------------------------------------- #include<bits/stdc++.h> using namespace std; struct INT { static const int MAXN = 8000; int s[MAXN], N; INT(int _N = 0)

NYOJ746——整数划分(四)

整数划分(四) 时间限制:1000 ms  |  内存限制:65535 KB 难度:3 描述 暑假来了,hrdv 又要留学校在参加ACM集训了,集训的生活非常Happy(ps:你懂得),可是他最近遇到了一个难题,让他百思不得其解,他非常郁闷..亲爱的你能帮帮他吗? 问题是我们经常见到的整数划分,给出两个整数 n , m ,要求在 n 中加入m - 1 个乘号,将n分成m段,求出这m段的最大乘积 输入 第一行是一个整数T,表示有T组测试数据 接下来T行,每行有两个正整数 n,m ( 1<= n <