枚举与模拟总结--常梓良

枚举就是列举出所有的可能性,然后从中选出想要的解。
1.火柴棒
题目描述
给你n根火柴棍,你可以拼出多少个形如“A+B=C”的等式?等式中的A、B、C是用火柴棍拼出的整数(若该数非零,则最高位不能是0)。用火柴棍拼数字0-9的拼法如图所示:在这里插入图片描述
注意:

加号与等号各自需要两根火柴棍

如果A≠B,则A+B=C与B+A=C视为不同的等式(A、B、C>=0)

n根火柴棍必须全部用上

输入格式
输入文件matches.in共一行,有一个整数n(n<=24)。

输出格式
输出文件matches.out共一行,表示能拼成的不同等式的数目。

样例数据
input

Input 1:
14

Input 2:
18
output

Output 1:
2

Output 2:
9
数据规模与约定
时间限制:1s1s
空间限制:256MB256MB

注释
【输入输出样例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
分析一下:
我们可以将许多组成后的数存到数组里,然后依次查询计算。
注意:
由于加号和等号各需两根火柴,所以我们最多可用24-2-2=20根。
所以最大加数为1111和1111。
我们可以来分解一下,

“1”需要2根。
“11”需要“1”+“1”=4根。
“111”需要“11”+“1”=4+2=6根。
所以摆n这个数所需的火柴数就等于a[n%10]+a[n/10]的和(n>=10)//a[i]记录的是摆“i”这个数字所需的火柴数。//代码如下
#include<bits/stdc++.h>
using namespace std;
int main()
{
freopen(“input.in”,“r”,stdin);
freopen(“output.out”,“w”,stdout);
int a[2222]={6,2,5,5,4,5,6,3,7,6};//给前九个数赋初值,并且数组要开到2222。预处理
int n,ans=0;
cin>>n;
n-=4;//预处理n
for(int i=10;i<=2222;i++)//预处理前2222个数
{
a[i]=a[i/10]+a[i%10];
}
for(int i=0;i<=1111;i++)
{
for(int j=0;j<=1111;j++)
{

	    if(n-a[i]-a[j]==a[i+j])
		ans++;
	}
}
cout<<ans<<endl;
return 0;

}
2.牛式
题目描述
下面是一个乘法算式,但是所有的数字都看不见了。
如果一个 * 可以是任何一个数字,想必这个虫食算有相当多的解;
xxx
× xx

  x x x

x x x

x x x x
但如果一个 * 只能从给定集合中选取数字,那么这个虫食算有多少个解呢?

输入格式
从文件 alpha2.in 中读入数据。

第一行有一个正整数 nn,代表可选数字的个数。

第二行有 nn 个用空格隔开的数字,这些数字只能是 11 到 99 中的一个,并且它们互不相同。这些数字表示一个 * 可以代表的数字。

输出格式
输出到文件 alpha2.out 中。

仅一个数,表示总的方案数。

样例
样例输入
5
2 3 4 6 8
样例输出
1
样例解释
下面显示了该式子满足样例输入条件的唯一解。

2 2 2
× 2 2

4 4 4
4 4 4

4 8 8 4
数据范围与提示
50%数据:1≤n≤5

100% 数据:1≤n≤9

分析一下:
因为我们要从集合中选数,且每一位上的的数都必须是集合中的数。
所以我们可以开一个五重循环,模拟每一位上的情况。
细节:进位。//代码如下
#include<bits/stdc++.h>
using namespace std;
int main()
{
freopen(“alpha2.in”,“r”,stdin);
freopen(“alpha2.out”,“w”,stdout);
int n,s[11];
int x1,x2,x3,y1,y2,y3,z1,z2,z3,z4;
int ans=0;
bool f[11]={};
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>s[i];
f[s[i]]=1;
}
for(int a=1;a<=n;a++)
{
for(int b=1;b<=n;b++)
{
for(int c=1;c<=n;c++)
{
for(int d=1;d<=n;d++)
{
for(int e=1;e<=n;e++)
{
x1=0;
x2=0;
x3=0;
y1=0;
y2=0;
y3=0;
z1=0;
z2=0;
z3=0;
z4=0;
x1+=s[e]*s[c];
if(x1>=10)
{
x2+=x1/10;
x1%=10;
}
x2+=s[e]*s[b];
if(x2>=10)
{
x3+=x2/10;
x2%=10;
}
x3+=s[e]*s[a];
if(x3>=10)
{
continue;
}

					y1+=s[d]*s[c];
					if(y1>=10)
					{
						y2+=y1/10;
						y1%=10;
					}
					y2+=s[d]*s[b];
					if(y2>=10)
					{
						y3+=y2/10;
						y2%=10;
					}
					y3+=s[d]*s[a];
					if(y3>=10)
					{
					   continue;
					}
					z1+=x1;
					z2+=x2+y1;
					if(z2>=10)
					{
						z3+=z2/10;
						z2%=10;
					}
					z3+=x3+y2;
					if(z3>=10)
					{
						z4+=z3/10;
						z3%=10;
					}
					z4+=y3;
					if(z4>=10)
					continue;
				    if(f[x1] && f[x2] && f[x3] && f[y1] && f[y2] && f[y3] && f[z1] && f[z2] && f[z3] && f[z4])
					ans++;
				}
			}
		}
	}
}
cout<<ans<<endl;
return 0;

}
3.连续累加加
题目描述
给你一个整数N和长度L, 现在要求你找X个连续的非负整数,使得它们的和是N, 同时要满足 X >= L, 你的任务是使得X最小,输出这连续的X个整数。

如果找不到这样的连续整数或者能找到但X > 100, 那么你输出-1。 也就是能找到满足题意的连续整数,且X < =100时,才输出这连续的X个非负整数。

输入格式
一行:两个整数: N 、L. 1 <= N <=10^9, 2 <= L <= 100.

输出格式
如果找到合法的连续整数,把它们从小到大输出,每行一个整数。 否则输出-1。

样例数据
input

18 2
output

5
6
7
数据规模与约定
经典题目

时间限制:1texts1texts
空间限制:256textMB

分析一下:
连续的几个数的求和公式为:
a+(a+1)+(a+2)+(a+3)+(a+4)+…+(a+n)=((a+(a+n))(n+1))/2。
所以2N=(a+a+n)(n+1)
所以2N/(n+1)=a+a+(n+1-1)
所以2N/(n+1)-(n+1)+1=2a
a的值就能求出来了!
注意:
a为连续数最开始的数,数列的长度为(n+1)//代码如下
#include<bits/stdc++.h>
using namespace std;
int main()
{
freopen(“sum.in”,“r”,stdin);
freopen(“sum.out”,“w”,stdout);
int x,n,l;
cin>>n>>l;
int len;
for(int len=l;len<=100;len++)
{
if(n
2%len0)
{
if((n*2/len-len+1)%2
0)
{
int dev=0;
for(int i=(n*2/len-len+1)/2;;i++)
{
if(dev==len)
return 0;
cout<<i<<endl;
dev++;
}
}
}
}
cout<<"-1"<<endl;
return 0;
}
4.最大连续和
题目描述
给定N个数,求这N(1 <=N <= 100,000) 个数的某个连续子序列的累加和,保证这个连续子序列的累加和最大。

输入格式
第一行:一个整数N。(1 <=N <= 100,000) 接下来N行,每行一个整数P_i(-1,000 <= P_i <= 1,000)。表示第i个数。

输出格式
一个整数,表示子序列的最大连续累加和。

样例数据
input

7
-3
4
9
-2
-5
8
-3
output

14
数据规模与约定
20% 数据保证 n≤20n≤
60%数据保证 n≤5000
100% 数据保证 n≤100000
时间限制:1s1s
空间限制:256MB256MB
注释
(4, 9, -2, -5, 8) => 14. 子序列不能为空!!

本人认为此题老刘的算法很妙。
因为这题的n的数据范围较大
正常的解法肯定会超时
分析一下:
既然我们不能用一般的解法,那就要另辟蹊径。
我们想一下,如果一个数为负数,那么它对数列的影响就是负面的,我们就应该直接放弃。还应该用一个变量来记录一下最大值。//代码如下
#include<bits/stdc++.h>
using namespace std;
int main()
{
freopen(“profits.in”,“r”,stdin);
freopen(“profits.out”,“w”,stdout);
int a[100001];
int n;
cin>>n;
int ans=0;
int sum=-100000;//用来记录
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
for(int i=1;i<=n;i++)//一重循环即可
{
ans+=a[i];//加上这个数
if(ans>sum)//记录这个数
sum=ans;
if(ans<0)//已经小于0了,舍弃
ans=0;//重新赋值
}
cout<<sum<<endl;//输出最大值
return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值