P2386 放苹果
题目描述
把 m 个同样的苹果放在 n 个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分法。(5,1,15,1,1 和 1,1,51,1,5 是同一种方法)
输入格式
第一行是测试数据的数目 t,以下每行均包括二个整数 m 和 n,以空格分开。
输出格式
对输入的每组数据 m 和 n,用一行输出相应的结果。
输入输出样例
输入
1 7 3
输出
8
输入
3 3 2 4 3 2 7
输出
2 4 2
说明/提示
对于所有数据,保证:1≤m,n≤10,0≤t≤20。
解题思路:
对于摆放的情况,就有可能出现所有盘子都有苹果或者是有盘子空着不放两种情况。
先设计一个apple(x,y)的函数来返回m个苹果放n个盘子的方法数,来探讨苹果的分配情况。
苹果的数量<盘子的数量,最多也就用上和苹果数量相同的盘子。
苹果的数量=盘子的数量,m个苹果放在m个盘子中的分法。
苹果的数量>盘子的数量,会出现两种情况,一是每个盘子都有苹果,二是有的盘子空着不放。那么只要分别求出这两种情况对应的放法数,两者相加就能得到答案了。
AC代码:
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
int m, n, t;
int apple(int x, int y)
{
if (x == 1 || y == 1 || x == 0) //终止条件
{
return 1;
}
if (x >= y) //苹果比盘子多
{
return apple(x, y - 1) + apple(x - y, y);
}
else //苹果比盘子少
{
return apple(x, x);
}
}
int main()
{
int i;
cin >> t;
for(i=0;i<t;i++)
{
cin >> m >> n;
cout << apple(m, n) << endl;
}
}
p1934 封印
题目描述
很久以前,魔界大旱,水井全部干涸,温度也越来越高。为了拯救居民,夜叉族国王龙溟希望能打破神魔之井,进入人界“窃取”水灵珠,以修复大地水脉。可是六界之间皆有封印,神魔之井的封印由蜀山控制,并施有封印。龙溟作为魔界王族,习有穿行之术,可任意穿行至任何留有空隙的位置。然而封印不留有任何空隙! 龙溟无奈之下只能强行破除封印。破除封印必然消耗一定的元气。为了寻找水灵珠,龙溟必须减少体力消耗。他可以在破除封印的同时使用越行术。
神魔之井的封印共有 n 层,每层封印都有一个坚固值。身为魔族的龙溟单独打破一层封印时需要消耗的元气为该层封印的坚固值和封印总层数 n 的平方的乘积; 但他运用越行术时,打破第 i 层到第 j 层封印(i<j)的总元气消耗为第 i, j 层封印的坚固值之和与第 i, j 层之间所有封印层(包括第 i, j 层)的坚固值之和的乘积。同时,为了不惊动蜀山,第 i, j 层封印的坚固值之和必须不大于一个固定值 t(单独打破时该层坚固值可以大于该值) 。
输入格式:
第一行包含两个正整数 n 和 t,按序表示封印层数和题中所述的固定值。
第二行为 n 个正整数a1~an,按序表示第 1 层到第 n 层封印的坚固值。
输出格式:
仅一行,包含一个正整数,表示最小消耗元气。
输入样例
6 10 8 5 7 9 3 5
输出样例
578
【样例说明】
先单独打破第一层,再用越行术从第二层直接打破到最后一层。 这样消耗元
气8 × 6^2+ (5 + 5) × (5 + 7 + 9 + 3 + 5) = 578。
【数据范围】
对于 10%的数据,n ≤ 10;
对于 50%的数据,n ≤ 100;
对于 70%的数据,n ≤ 500;
对于 100%的数据,n ≤ 1000,ai(1 ≤ i ≤ n) , t ≤ 20000。
解题思路:
本题想到用DP来解决。
我们令f[i]表示打破前i层封印消耗元气的最小值,则状态转移方程如下:
f[i]=max{f[i−1]+a[i]*n^2,f[k]+(a[k+1]+a[i])*sum(k+1,i)|0<k+1<i,a[k+1]+a[i]≤k}
状态转移方程写好后,问题在于求sum(k+1,i)时如果遍历一遍需要O(n)的复杂度。这样总复杂度为k(n^3),50-70分。
这个复杂度可以用预处理前缀和的方法来优化。用S[i]表示从a[1]到a[i]的
总和,则sum(k+1,i)=S[i]-S[k]。这样总复杂度为k(n^2),可以通过所有测试点。
AC代码:
#include<iostream>
using namespace std;
int n,t;
long long f[1003],s[1003],a[1003];
int main()
{
int i,j;
cin>>n>>t;
int m=n*n;
for(i=1;i<=n;i++)
{
cin>>a[i];
s[i]=s[i-1]+a[i];
}
for(i=1;i<=n;i++)
{
long long ans=m*a[i]+f[i-1];
for(j=1;j<i;j++)
{
if(a[i]+a[j]>t)continue;
ans=min(ans,(a[i]+a[j])*(s[i]-s[j-1])+f[j-1]);
}
f[i]=ans;
}
cout<<f[n];
return 0;
}
p5732 杨辉三角形
解题思路:
当指考虑小范围的值时,我们可以直接根据杨辉三角形的规律:第i行第j列的值=第i-1行第j列的值+第i-1行第j-11列的值,来把前50个杨辉三角形的数存入数组中,最后通过一个循环来查找就可以得到20%的分数。
AC代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 10100;
LL dp[N][N]; //用来存入杨辉三角形的每一个数
LL sk[N]; //记入每个数是第几个数
int s = 1;
int n;
int main()
{
int i;
cin >> n,j;
dp[0][0] = 1;
for (i = 1; i <= 50; i++)
{
for (j = 1; j <= i; j++)
{
dp[i][j] = dp[i - 1][j] + dp[i - 1][j - 1]; //杨辉三角形的规律
sk[s++] = dp[i][j];
}
}
for (ii = 1; i <= 10000; i++)
{
if (sk[i] == n)
{ //第一次相等即为该数第一次出现的位置
cout << i;
break;
}
}
return 0;
}
! _ !