火柴棒等式
题目描述
现在我们给昆昆n根火柴棍,请算算以昆昆的聪明才智昆昆可以拼出多少个形如“A+B=C”的等式?等式中的A、B、C是用火柴棍拼出的整数(若该数非零,则最高位不能是0)。用火柴棍拼数字0-9的拼法如图所示:
注意:
- 加号与等号各自需要两根火柴棍
- 如果A≠B,则A+B=C与B+A=C视为不同的等式(A,B,C>=0)
- n根火柴棍必须全部用上
输入格式
一个整数n(n<=24)。
输出格式
一个整数,能拼成的不同等式的数目。
输入输出样例
输入
14
输出
2
输入
18
输出
9
说明/提示
【输入输出样例1】
2个等式为0+1=1和1+0=1。
【输入输出样例2】
9个等式为:
0+4=4
0+11=11
1+10=11
2+2=4
2+7=9
4+0=4
7+2=9
10+1=11
11+0=11
解
由于1111+1=1112已经用了25根小棒,已经超过了题目24根小棒的数据范围,所以可以直接枚举相加的两个数,上界为1111,
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
int a[10]={6,2,5,5,4,5,6,3,7,6};
//'=''+'==2
//0==6
//1==2
//2==5
//3==5
//4==4
//5==5
//6==6
//7==3
//8==7
//9==6
int matchs(int num){ //一个用来计算一个数需多少个火柴棒的函数
int i,k=0; //K是火柴棒的数量
for(i=num;i!=0;i/=10)k+=a[i%10]; //将这个数字每一位的火柴棒的数量都计算出来
if(num==0)k+=a[0]; //有一种特殊情况:数字为0此时不会执行上述程序,所以加一个
return k;
}
int main()
{
int n,res = 0;
cin >> n;
for(int i = 0;i<1000;i ++)
for(int j = 0;j <1000;j++)//表示范围在1000左右
{
if(matchs(i) + matchs(j) +matchs(i+j)+4 == n) res++;
}
cout << res <<endl;
return 0;
}
王姐拼木棒
题目背景
上道题中,王姐劈了一地的木棒,现在她想要将木棒拼起来。
题目描述
有 n 根木棒,现在从中选 4 根,想要组成一个正三角形,问有几种选法?
答案对 10^9+7 取模。
输入格式
第一行一个整数 n。
第二行 n 个整数,第 i 个整数 ai 代表第 i 根木棒的长度。
输出格式
一行一个整数代表答案。
输入输出样例
输入
4
1 1 2 2
输出
1
说明/提示
数据规模与约定
- 对于 30%30% 的数据,保证n≤5×10^3。
- 对于 100%100% 的数据,保证1≤n≤105,0≤ai≤5×103。
解
题里面说,4根棍子拼成一个正三角形(等边三角形)
别像我题都不看清楚就在那里分析半天最后才看到这个!!!
若设这四根棍子长度为a,b,c,d且a≥b>c≥d
那很容易得到 (真的很容易):
a=b=c+d
排列组合
#include<iostream>
#include<fstream>
#include<cstdio>
#include<cmath>
#include<queue>
#include<string>
#include<cstring>
#include<string.h>
#include<algorithm>
#include<iomanip>
using namespace std;
int n,b[5010],a[1000010],minn=1e9,maxx;
long long ans;
const int mod=1e9+7;
int main()
{
cin>>n;
for(int i=1; i<=n; i++)
{
cin>>a[i];//输入
minn=min(minn,a[i]);//找出最小的边
maxx=max(maxx,a[i]);//找出最大的边
b[a[i]]++;//数组记录边数
}
for(int i=minn+1; i<=maxx; i++)//这里从最小量+1开始枚举,是因为最小量不可能有两个比它更小的两组成
{
if(b[i]>1)//如果这个数字有一个以上,外层有多个相同的边
for(int j=minn; j<=i/2; j++)//从最小边开始枚举,注意边算边取模
if(b[j]>=1&&b[i-j]>=1)//如果他可以被两个比他小的两组成
{//这里一定要清楚i和j表示的是长度而不是个数
if(j*2!=i)ans=(ans+(b[i]*(b[i]-1)/2)*b[j]*b[i-j]%mod)%mod;//统计,如果两边不相同
//选两条Cn2,剩下不同的各选一条Cn1
else if(b[j]>1)ans=(ans+((b[i]*(b[i]-1)/2)*(b[j]*(b[j]-1)/2)%mod)%mod)%mod;//统计,相同
//各选两条cn2
}
}
cout<<ans%mod;//输出
return 0;
}
烤乳猪
题目描述
烤乳猪是一种流行的美食。为了做好烤乳猪,厨师必须谨慎选择食材,以在保持传统风味的同时尽可能获得最全面的味道。星瑶有 n 种可支配的配料。对于每一种配料,我们知道它们各自的酸度 s 和苦度 b。当我们添加配料时,总的酸度为每一种配料的酸度总乘积;总的苦度为每一种配料的苦度的总和。
众所周知,美食应该做到口感适中,所以我们希望选取配料,以使得酸度和苦度的绝对差最小。
另外,我们必须添加至少一种配料,因为没有任何食物以水为配料的。
输入格式
第一行一个整数 n,表示可供选用的食材种类数。
接下来 n 行,每行 2个整数 si 和 bi,表示第 i 种食材的酸度和苦度。
输出格式
一行一个整数,表示可能的总酸度和总苦度的最小绝对差。
输入输出样例
输入
1
3 10
输出
7
输入
2
3 8
5 8
输出
1
输入
4
1 7
2 6
3 8
4 9
输出
1
说明/提示
数据规模与约定
对于 100% 的数据,有 1≤n≤10,且将所有可用食材全部使用产生的总酸度和总苦度小于 1×109,酸度和苦度不同时为 1和 0。
注意数据范围,一道简单的dfs
#include<bits/stdc++.h>
using namespace std;
long long int s[20],b[20],f[20];
long long int n,j,c=1,y=0,ans=1000000010;
//s表示酸度,b表示甜度,f记录是否查找
//c记录酸度,y记录甜度
void dfs(int x)
{
if(x>n) //最多选n种调料,超过返回
{
return;
}
else
{
for(int i=1;i<=n;i++)
{
if(f[i]==0) //没有查找过的才操作
{
c *= s[i];
y += b[i];
ans=min(ans,abs(c-y)); //取最小值
f[i]=1; //记录
dfs(x+1);
//回溯
f[i]=0; //取消记录
c/=s[i];
y-=b[i];
}
}
}
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>s[i]>>b[i];
}
dfs(1);
cout<<ans;
}
阿晨考前临时抱佛脚
题目背景
阿晨的大学生活非常的颓废,平时根本不学习。但是,临近期末考试,他必须要开始抱佛脚,以求不挂科。
题目描述
这次期末考试,阿晨需要考 44 科。因此要开始刷习题集,每科都有一个习题集,分别有 s*1,s2,s3,*s4道题目,完成每道题目需要一些时间,可能不等。
阿晨有一个能力,他的左右两个大脑可以同时计算 2 道不同的题目,但是仅限于同一科。因此,阿晨必须一科一科的复习。
由于 阿晨还急着去处理java的 bug,因此他希望尽快把事情做完,所以他希望知道能够完成复习的最短时间。
输入格式
本题包含 5行数据:第 1 行,为四个正整数 s_1,s_2,s_3,s_4s1,s2,s3,s4。
第 2 行,为 A1,A2,…,As1 共 s1 个数,表示第一科习题集每道题目所消耗的时间。
第 3 行,为 B1,B2,…,Bs2 共s2 个数。
第 4 行,为 C1,C2,…,Cs3 共s3 个数。
第 5 行,为 D1,D2,…,Ds4 共s4 个数,意思均同上。
输出格式
输出一行,为复习完毕最短时间。
输入输出样例
输入
1 2 1 3
5
4 3
6
2 4 3
输出
20
说明/提示
1≤s1,s2,s3,s4≤20。
1≤A1,A2,…,As1,B1,B2,…,Bs2,C1,C2,…,Cs3,D1,D2,…,Ds4≤60。
解
被贪心骗了奶奶滴
感觉是dp,对于一道题只有两个状态,一是加到左脑,二是加到右脑,所以是01背包
这里还可以用另一个思想,将一边的脑子加到最接近一半则另一边脑子时间就是正解
保证比t/2小,又要使取得的价值尽量大,可以转化为一个费用与价值相同的背包问题。背包大小为t/2,一个题目的费用和价值相等,都是所耗的时间。
假设背包求得的最大价值为v,显然另一个脑耗时为t-v,则总耗时为max(v,t-v)。
#include<bits/stdc++.h>
using namespace std;
int a[5],i,j,k,sum,t,homework[21],dp[2501];
int main(){
for(i=1;i<=4;i++)
cin>>a[i];
for(i=1;i<=4;i++){
sum=0;
for(j=1;j<=a[i];j++)
{cin>>homework[j];//输入
sum+=homework[j];}//总时间累加,这个相当于就是背包
for(j=1;j<=a[i];j++)
for(k=sum/2;k>=homework[j];k--)//只要是总和的一半
dp[k]=max(dp[k],dp[k-homework[j]]+homework[j]);//01背包
t+=sum-dp[sum/2];//累加为另一个脑子,最接近一半,肯定是小于等于一半的
if(i!=4) memset(dp,0,sizeof dp);
}
cout<<t;//输出
return 0;
}