2011年12月17日
摘要: UVA_10616 我们可以用f[i][j][k]表示选到第i个数时一共选了j个数且它们的和模D的值为k,由于第i个数可以选也可以不选,那么就有f[i][j][k]=f[i-1][j][k]+f[i-1][j-1][x],其中x满足0<=x<D且(x+a[i]%D)%D=k,边界为f[0][0][0]=1。#include<stdio.h>#include<string.h>#define MAXN 210#define MAXD 30#define MAXM 15int N, Q, M, D;long long int a[MAXN], f[MAXN][M 阅读全文
posted @ 2011-12-17 21:49 Staginner 阅读(387) 评论(0) 推荐(0) 编辑
摘要: UVA_10912 数据乍看起来比较大,实际上长度不会超过26,总的权值不会超过351。 我们可以用f[i][j][k]表示选到第i个字符时当前字符串长度为j总权值为k的情况总数,由于字符i可选也可不选,那么f[i][j][k]=f[i-1][j][k]+f[i-1][j-1][k-i],边界为f[0][0][0]=1。#include<stdio.h>#include<string.h>int f[30][30][400];int L, S;void prepare(){ int i, j, k; memset(f, 0, sizeof(f)); f[0][0][0] 阅读全文
posted @ 2011-12-17 20:02 Staginner 阅读(723) 评论(0) 推荐(0) 编辑
摘要: UVA_10721 我们可以设f[i][j]表示第i个bar以第j个unit为结尾时情况的总数,那么f[i][j]=sum{f[i-1][k]},j-k<=M。#include<stdio.h>#include<string.h>#define MAXD 60int N, K, M;long long int f[MAXD][MAXD];void solve(){ int i, j, k; memset(f, 0, sizeof(f)); for(i = 1; i <= M && i <= N; i ++) f[1][i] = 1; f 阅读全文
posted @ 2011-12-17 19:12 Staginner 阅读(419) 评论(0) 推荐(0) 编辑
摘要: UVA_10943 这个题目的描述好像有点问题,本意其实是让求K个不大于N的非负整数有多少种情况使得K个整数的和为N。 这个问题可以等效成有N个相同的小球放到K个不同的盒子里,每个盒子可以为空,求一共多少种放置的方法?答案容易用隔板放求得为C(N+K-1,K-1),但由于组合数的递推公式里面有除法,所以我们不能每步都用模运算。鉴于这个题目N和K比较小,我们可以用递推公式C(m,n)=C(m-1,n)+C(m-1,n-1)来预处理出各个组合数的值。#include<stdio.h>#include<string.h>#define MAXD 210#define D 10 阅读全文
posted @ 2011-12-17 18:49 Staginner 阅读(887) 评论(0) 推荐(1) 编辑
摘要: UVA_10081 我们可以用f[i][j]表示第i个字符为j时的tight words的比率,那么有f[i][j]=1.0/(K+1)*(f[i-1][j-1]+f[i-1][j]+f[i-1][j+1]),当然括号里面的三项不一定都存在,分情况讨论一下即可。#include<stdio.h>#include<string.h>#define MAXK 15#define MAXN 110int N, K;double f[MAXN][MAXK];void solve(){ int i, j; double res = 0; for(i = 0; i <= K; 阅读全文
posted @ 2011-12-17 13:31 Staginner 阅读(541) 评论(0) 推荐(0) 编辑
摘要: UVA_10128 这个题目一开始用排列组合去想的,比较麻烦,后来看了别人的解题报告,发现用递推去想比较简单。 先说说排列组合的思路吧,最高的人肯定是挡不住的,然后最高的人把队列分成了两部分,两部分分别从某个方向看过去人数分别为P-1和R-1(因为这个时候我们不考虑最高的人)。由于两部分是对称的,因此我们不妨f[i][j]表示i个人时,从一个方向看过去能够看到j个人的情况种数,这样我们只要把f[i][j]都求出来了,最后再用组合数分一下最高的人两边的人数即可。 在计算f[i][j]的时候思路也基本一样,由于从一个方向看过去,我们不妨假设从左向右看,这样最高的人还是不会被挡住,左边的人要构... 阅读全文
posted @ 2011-12-17 12:36 Staginner 阅读(614) 评论(0) 推荐(0) 编辑
摘要: UVA_10516 我们不妨设在n叉树时,不超过i层的树的种类为f[i],那么对于由i-1变到i时,我们新添的根节点要么所有子树都有,即共有f[i-1]^n种情况,要么一个子树也没有,即只有一种情况,于是我们就可以得到递推式f[i]=f[i-1]^n+1,最后输出f[d]-f[d-1]即可。 此外,这个题目说最后结果保证200位以内,但不是所有题目范围之内的数据都是200位以内的,只不过测试数据里面没有罢了,因此我们干脆不要去预处理了,有些结果是相当庞大的。import java.math.BigInteger;import java.util.Scanner;public class M.. 阅读全文
posted @ 2011-12-17 10:14 Staginner 阅读(488) 评论(0) 推荐(0) 编辑
摘要: UVA_10247 我们不妨先对k叉树由n-1层变成n层时这一情况讨论一下,看看是否能得到一个递推式。 不妨设f[i]表示k叉树n层时的方案种数,设g[i]为k叉树i层时顶点的个数,首先变成n层时,根节点必须填最小的数,根节点的子节点呢?由于标签都是不同的,那么每棵子树都可以从剩下的标签中选出g[n-1]个标签即可。这样我们就得到了递推式f[n]=multiply{C(i*g[n-1],g[n-1])*f[n-1]}(1<=i<=k)。 于是这样我们就可以先把所有结果预处理出来了。import java.math.BigInteger;import java.util.Scanne 阅读全文
posted @ 2011-12-17 00:07 Staginner 阅读(774) 评论(0) 推荐(0) 编辑