• poj3181【Dollar Dayz】


    **
    做完这道题,心里五味陈杂,明明是最水的一道题,我却做了最长的时间。
    题意是求用1~k的和表示n的方案数。
    显然是个计数dp,但我不会。思考半小时未果。
    然后找尹鹏哲,他给我讲了个错的dp方程,结果调试半小时未果,看了别人的代码,发现别人虽然滚了一维,但和尹鹏哲讲的十分相似。
    后来我又想了想,觉得尹鹏哲的dp方程有点问题,自己改了一下,但当时并没有验证。实际上,由于对题解方程错误理解,当时我已经形成了思维定势,认为方程是对的,却没有发现方程中一个十分微小但十分致命的错误——我把完全背包和01背包的模型搞混了。正是这个错误,让我调+改又浪费了两个小时。
    好了,废话说了这么多,只是想让自己记住这次教训,希望下次不要再犯。(但背包问题的模型又多,变化又复杂,所以只能希望了),下面写题解。
    先讲二维的:
    设f[i][j]表示用前i个物品,刚好凑出体积j的方案数。这个状态很好想。
    然后是转移,就是在这里我的思维出现了偏差。
    开始,尹鹏哲告诉我的是f[i][j]+=f[i-1][j-i],这个与一维方程一模一样,显然是不对的,但我太信任尹鹏哲,所以并没有细想。
    后来,受尹鹏哲的启发,我自己写出来的方程是f[i][j]=f[i-1][j-i]+f[i-1][j],与组合数的递推关系一样,表示第i件物品选与不选。
    这个方程咋看上去没问题,实际上,这道题与组合数有着本质的区别,组合数每个物品只能选一次,而这道题一个数字显然可以用多次。但傻逼的我忽视了这个差别,结果狂WA不止。
    换成背包问题的计数的话,组合数实际上是01背包的方案数,而这道题实际上是完全背包的方案数!
    所以,dp方程应该为:f[i][j]=f[i][j-i]+f[i-1][j]
    滚成一维就很简单了:f[j]+=f[j-i]
    实际上,完全背包和01背包的代码十分相似,若碰到一定要想清楚!
    另:要打高精度,详见一维代码。**
    二维:

    #include <bits/stdc++.h>
    using namespace std;
    
    #define db double
    #define ll long long
    #define RG register
    
    inline int gi()
    {
    	RG int ret; RG bool flag; RG char ch;
    	ret=0, flag=true, ch=getchar();
    	while (ch < '0' || ch > '9')
    		ch == '-' ? flag=false : 0, ch=getchar();
    	while (ch >= '0' && ch <= '9')
    		ret=(ret<<3)+(ret<<1)+ch-'0', ch=getchar();
    	return flag ? ret : -ret;
    }
    
    const db pi = acos(-1.0);
    const int N = 142857, inf = 1<<30;
    
    int f[205][2005];
    
    int main()
    {
    	freopen("Dollar_Dayz.in","r",stdin);
    	freopen("Dollar_Dayz.out","w",stdout);
    	int n,m,i,j;
    	n=gi(), m=gi();
    	f[1][0]=1;
    	// 两种都可
    	// for (i=1; i<=m; ++i)
    	// 	for (j=0; j<=n; ++j)
    	// 		{
    	// 			if (j >= i)
    	// 				f[i][j]=f[i][j-i];
    	// 			f[i][j]+=f[i-1][j];
    	// 		}
    	for (i=1; i<=m; ++i)
    		for (j=0; j<=n; ++j)
    			f[i][j+i]+=f[i][j], f[i+1][j]=f[i][j];
    	printf("%d
    ",f[m][n]);
    	return 0;
    }
    

    一维:

    #include <bits/stdc++.h>
    using namespace std;
    
    #define db double
    #define ll long long
    #define RG register
    
    inline int gi()
    {
    	RG int ret; RG bool flag; RG char ch;
    	ret=0, flag=true, ch=getchar();
    	while (ch < '0' || ch > '9')
    		ch == '-' ? flag=false : 0, ch=getchar();
    	while (ch >= '0' && ch <= '9')
    		ret=(ret<<3)+(ret<<1)+ch-'0', ch=getchar();
    	return flag ? ret : -ret;
    }
    
    const db pi = acos(-1.0);
    const int N = 1e3+5, inf = 1<<30;
    const ll lim = 1e18;  //要开 ll
    
    ll f[N],g[N];
    
    int main()
    {
    	freopen("Dollar_Dayz.in","r",stdin);
    	freopen("std.out","w",stdout);
    	int n,m,i,j;
    	n=gi(), m=gi();
    	g[0]=1;
    	for (j=1; j<=m; ++j)
    		for (i=j; i<=n; ++i)
    			{
    				f[i]+=f[i-j], g[i]+=g[i-j];
    				if (g[i] >= lim)
    					f[i]+=g[i]/lim, g[i]%=lim;
    			}
    	if (f[n])
    		printf("%lld%lld
    ",f[n],g[n]);
    	else
    		printf("%lld
    ",g[n]);
    	return 0;
    }
    
  • 相关阅读:
    Javascript内容整理——BOM
    前端实现excel报表,vue+luckysheet
    代码转图片 的一个好用网站
    推荐一个非常好用前端在线编辑器!!! 一点都不卡
    前端常用的一些网站
    vue中使用moment,如何按需打包?
    better-scroll
    时间线
    碎纸屑动画
    动画
  • 原文地址:https://www.cnblogs.com/y142857/p/7508274.html
Copyright © 2020-2023  润新知