蓝桥杯练习||洛谷【算法1-3】暴力枚举

目录

P2241 统计方形(数据加强版)

P1036 [NOIP2002 普及组] 选数

P1157 组合的输出

P3392 涂国旗

P1217 [USACO1.5] 回文质数 Prime Palindromes

P1149 [NOIP2008 提高组] 火柴棒等式

P3799 妖梦拼木棒

P2392 kkksc03考前临时抱佛脚


P2241 统计方形(数据加强版)

题目描述

有一个×m 方格的棋盘,求其方格包含多少正方形、长方形(不包含正方形)。

输入格式

一行,两个正整数n,m(n≤5000,m≤5000)。

输出格式

一行,两个正整数,分别表示方格包含多少正方形、长方形(不包含正方形)。

输入样例

2 3

输出样例

8 10

题解 

一、正方形个数

1.固定正方形的右下角(i,j)

2.此时正方形的个数为Min(i,j).

3.枚举右下角,求和即可。

二、长方形个数

1.矩形个数-正方形个数.

2.固定矩形右下角(i,j)

3.此时矩形个数为i*j,求和即可.

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
long long n,m,sum,sum1; 
int main()
{
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	{
	  for(int j=1;j<=m;j++)
	  {
	    sum+=min(i,j);
	    sum1+=i*j;
	  }
	}
	cout<<sum<<" "<<sum1-sum<<endl;
	return 0;
}

P1036 [NOIP2002 普及组] 选数

题目描述

已知 n 个整数1,2,⋯ ,x1​,x2​,⋯,xn​以及1个整数 k(k<n)。从 n 个整数中任选 k 个整数相加,可分别得到一系列的和。例如当n=4,k=3,4个整数分别为3,7,12,19时,可得全部的组合与它们的和为:

3+7+12=22

3+7+19=29

7+12+19=38

3+12+19=34

现在,要求你计算出和为素数共有多少种。

例如上例,只有一种的和为素数:3+7+19=29。

输入格式

第一行两个空格隔开的整数n,k(1≤n≤2,k<n)。

第二行n个整数,分别为x1​,x2​,⋯,xn​(1≤xi​≤5×1e6)。

输出格式

输出一个整数,表示种类数。

输入样例

4 3
3 7 12 19

输出样例

1

题解 

#include<iostream>
using namespace std;
int n,k,num;
int a[25];
//判断素数 
bool isprime(int a)
{
	for(int i=2;i*i<a;i++)
	{
		if(a%i==0) return false;
	}
	return true;
}
//递归 
void res(int start,int count,int sum)
{
	//start:开始选数的位置
	//count:已经选了几个数 
	//sum: 目前所选数之和 
	int i;
	if(count==k && isprime(sum))
	{
		num++;
		//判断所选的k个数之和是否为素数
		//num统计符合条件的和的个数 
	}
	for(int i=start;i<=n;i++)
	{
		res(i+1,count+1,sum+a[i]);
	}
}
int main()
{
	cin>>n>>k;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
	}
	res(1,0,0);//从第一个数开始搜索,找到0个数,目前和为0 
	cout<<num<<endl;
	return 0;
}

P1157 组合的输出

题目描述

排列与组合是常用的数学方法,其中组合就是从 n 个元素中抽出 r 个元素(不分顺序且r≤n),我们可以简单地将n个元素理解为自然数1,2,…,n,从中任取 r 个数。

现要求你输出所有组合。

例如n=5,r=3,所有组合为:123,124,125,134,135,145,234,235,245,345。

输入格式

一行两个自然数 n,r(1<n<21,0≤r≤n)。

输出格式

所有的组合,每一个组合占一行且其中的元素按由小到大的顺序排列,每个元素占三个字符的位置,所有的组合也按字典顺序。

注意哦!输出时,每个数字需要 33 个场宽。以 C++ 为例,你可以使用下列代码:

cout << setw(3) << x;

 输出占3个场宽的数x。注意你需要头文件 iomanip

输入样例

5 3

输出样例

  1  2  3
  1  2  4
  1  2  5
  1  3  4
  1  3  5
  1  4  5
  2  3  4
  2  3  5
  2  4  5
  3  4  5

next_permutation函数

头文件:<algorithm>

作用:列举数字所有排列方式

生成给定序列的下一个较大排序,直到序列按降序排列为止。到这里还需要强调的一点是,如果你希望生成所有的排列方式,一定要先将序列按升序排列,这里可以与sort函数结合起来使用,先用sort升序排列,再调用next_permutation函数。

#include<iostream>
#include<algorithm>
#include<iomanip>
using namespace std;
int a[25];//a[i]代表是否选第i个数,0选,1不选
int n,r;
int main()
{
	cin>>n>>r;
	for(int i=r+1;i<=n;i++) a[i]=1;//不选的数赋初值 
	do//使用while会跳过1,2,3这种最开始的排列情况。
	{
		for(int i=1;i<=n;i++)
			if(a[i]==0) cout<<setw(3)<<i;//如果是0就输出,注意三个常宽
		cout<<endl;//换行 
	}while(next_permutation(a+1,a+1+n));
	return 0;
}

P3392 涂国旗

题目描述

某国法律规定,只要一个由N×M个小方块组成的旗帜符合如下规则,就是合法的国旗。

  • 从最上方若干行(至少一行)的格子全部是白色的;
  • 接下来若干行(至少一行)的格子全部是蓝色的;
  • 剩下的行(至少一行)全部是红色的;

现有一个棋盘状的布,分成了 N 行 M 列的格子,每个格子是白色蓝色红色之一,小 a 希望把这个布改成该国国旗,方法是在一些格子上涂颜料,盖住之前的颜色。

小a很懒,希望涂最少的格子,使这块布成为一个合法的国旗。

输入格式

第一行是两个整数N,M。

接下来N行是一个矩阵,矩阵的每一个小方块是W(白),B(蓝),R(红)中的一个。

输出格式

一个整数,表示至少需要涂多少块。

输入样例

4 5
WRWRW
BWRWB
WRWRW
RWBWR

输入样例

11

样例说明

目标状态是: 

WWWWW
BBBBB
RRRRR
RRRRR

 一共需要改11个格子。

数据范围

对于100%的数据,N,M≤50。

struct是用来定义一个结构体类型的关键字。结构体是一种用户自定义的数据类型,可以包含不同类型的数据成员,这些成员可以被同时访问,例如:

struct Person {
    string name;
    int age;
};

void是用来表示函数的返回类型的关键字。当一个函数不返回任何数值时,可以将其返回类型声明为"void"。例如:

void doSomething() {
    // 函数体
}

inline是用来告诉编译器将函数的代码直接插入到调用代码中,而不是通过函数调用的方式来执行。这样可以减少函数调用的开销,提高程序的执行效率。在C++中,可以通过在函数声明或定义前面加上"inline"关键字来指示编译器将该函数作为inline函数处理。例如:

inline int add(int a, int b) {
    return a + b;
}
#include<iostream>
#include<algorithm>
using namespace std;
int n,m;
int sum=0x7fffffff;//定义sum为无穷大 
int w[55],b[55],r[55];//w,b,r分别存储前几行需要修改的颜色 
string s;//以字符串形式输入每行,避免二维字符数组超时 
inline int check(char c)//定义函数,查找每行需要修改对应的颜色c 
{
	int tot=0;
	for(int i=0;i<m;i++)
	{
		if(s[i]!=c) tot++;
	}
	return tot;
}
int main()
{
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	{
		cin>>s;
		w[i]=w[i-1]+check('W');
		b[i]=b[i-1]+check('B');
		r[i]=r[i-1]+check('R');
	}
	for(int i=1;i<n-1;i++)
	{
		for(int j=1+i;j<n;j++)//根据题目条件,w\b\r至少一行,所以不取=
		{
			sum=min(sum,w[i]+b[j]-b[i]+r[n]-r[j]);
		}
	}
	cout<<sum;
	return 0;
}

P1217 [USACO1.5] 回文质数 Prime Palindromes

题目描述

因为 151151 既是一个质数又是一个回文数(从左到右和从右到左是看一样的),所以 151151 是回文质数。

写一个程序来找出范围[a,b](5≤a<b≤100,000,000)(一亿)间的所有回文质数。

输入格式

第一行输入两个正整数 a 和 b。

输出格式

输出一个回文质数的列表,一行一个。

输入样例

5 500

输出样例 

5
7
11
101
131
151
181
191
313
353
373
383

说明/提示

提示 1: 找出所有的回文数再判断它们是不是质数(素数)。

提示 2: 要产生正确的回文数,你可能需要几个像下面这样的循环。

//产生长度为5的回文数
for (d1 = 1; d1 <= 9; d1+=2) {    // 只有奇数才会是素数
     for (d2 = 0; d2 <= 9; d2++) {
         for (d3 = 0; d3 <= 9; d3++) {
           palindrome = 10000*d1 + 1000*d2 +100*d3 + 10*d2 + d1;//(处理回文数...)
         }
     }
 }

题解

1.回文数少,所以先判断回文,再判断质数(顺序错误会超时)

2.偶数位的回文数(除了11)必然不是质数

#include<iostream>
using namespace std;
int l,r;
bool check1(int x)//判断位数 
{
	if((10<=x&&x<=100&&x!=11)||(1000<=x&&x<=10000)) return 0;
	if((100000<=x&&x<=1000000)||(10000000<=x&&x<=100000000)) return 0;
	return 1;
}
bool check2(int x)//判断回文 
{
	int a[20],flag=1;
	while(x>0)
	{
		a[flag]=x%10;
		x/=10;
		flag++;
	}
	for(int i=1;i<=flag/2;i++)
	{
		if(a[i]!=a[flag-i]) return 0;//不符合回文 
	}
	return 1;
}
bool check3(int x) //判断质数 
{
	if(x==2) return 1;
	for(int i=2;i*i<=x;i++)
	{
		if(x%i==0) return 0;
	}
	return 1;
}
int main()
{
	scanf("%d %d",&l,&r);
	if(l==2) printf("2\n");//特判质数2 
	if(l%2==0) l++;//从奇数开始 
	r=min(9999999,r);//再大的数都不可能是回文质数 
	for(int i=l;i<=r;i=i+2)//枚举每一个奇数
	{
		if(check1(i)==0) continue;
		if(check2(i)==0) continue;
		if(check3(i)==0) continue;
		printf("%d\n",i);//printf比cout快 
	}
	return 0;
}

P1149 [NOIP2008 提高组] 火柴棒等式

题目描述

给你 n 根火柴棍,你可以拼出多少个形如A+B=C 的等式?等式中的 A、B、C 是用火柴棍拼出的整数(若该数非零,则最高位不能是 0)。用火柴棍拼数字0∼9 的拼法如图所示:

注意:

  1. 加号与等号各自需要两根火柴棍;
  2. 如果 A≠B,则A+B=C 与B+A=C 视为不同的等式(A,B,C≥0);
  3. n 根火柴棍必须全部用上。

输入格式

一个整数n(1≤n≤24)。

输出格式

一个整数,能拼成的不同等式的数目。

输入样例1

14

输出样例1

2

输入样例2

18

输出样例2

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。

题解

#include<iostream>
using namespace std;
int n,s;
int a[2001]={6};//数组的首元素的值为6,其余元素的值为0。
int c[10]={6,2,5,5,4,5,6,3,7,6};
int main()
{
        cin>>n;
        for(int i=1;i<=2000;i++)
        {
                int j=i;
                while(j>=1)//求每个数所用的火柴棒
                {
                        a[i]+=c[j%10];
                        j/=10;
                }
        }
        for(int i=0;i<=1000;i++)
        {
                for(int j=0;j<=1000;j++)
                if(a[i]+a[j]+a[i+j]+4==n)s++;//还有加号与等号
        }
        printf("%d",s);
        return 0;
}

P3799 妖梦拼木棒

题目描述

有 n 根木棒,现在从中选 4 根,想要组成一个正三角形,问有几种选法?

答案对1e9+7 取模。

输入格式

第一行一个整数 n。

第二行往下 n 行,每行 1 个整数,第 i 个整数ai​ 代表第 i 根木棒的长度。

输出格式

一行一个整数代表答案。

输入样例

4 
1
1
2
2

输出样例

1

说明/提示

数据规模与约定

  • 对于30%的数据,保证n≤5×1e3。
  • 对于100%的数据,保证1≤n≤1e5,1≤ai​≤5×1e3。

题解

知识点:组合数,暴力

由4根木棒组成一个正三角形,则必有 2根长度相等。
且另外2根长度之和,等于 前2根相等的木棒 的长度。

#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int kmax=1e6+10;
const ll kmod=1e9+7;
ll n,ans,maxa,num[kmax],a[kmax];
ll c(ll n,ll k)//组合数 
{
	//求得从n个数中取出k个数的组合
	//最多取两根木棍,采用特判1/2两种 
	return (k==1ll ? n : n*(n-1)/2ll)%kmod; 
} 
int main()
{
	scanf("%lld",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%lld",&a[i]);
		maxa=max(maxa,a[i]);
		num[a[i]]++;//统计每种长度木棍根数 
	}
	for(int i=2;i<=maxa;i++)//枚举两根相等的边 
	{
		if(num[i]>=2ll)
		{
			ll time=c(num[i],2ll)%kmod;//统计组合数
			for(int j=1;j<=i/2;j++)//枚举被合成的边(到i / 2即可)
			{
				if(j!=i-j&&num[j]>=1&&num[i-j]>=1)//用来合成的木棒长度不等 
					ans+=time*c(num[j],1ll)*c(num[i-j],1ll)%kmod;
				if(j==i-j&&num[j]>=2)//用来合成的木棒长度相等 
					ans+=time*c(num[j],2ll)%kmod;
				ans%=kmod;
			}
		} 
	}
	cout<<ans;
	return 0;
}

P2392 kkksc03考前临时抱佛脚

题目描述

这次期末考试,kkksc03 需要考 4 科。因此要开始刷习题集,每科都有一个习题集,分别有s1​,s2​,s3​,s4​ 道题目,完成每道题目需要一些时间,可能不等(A1​,A2​,…,As1​​,B1​,B2​,…,Bs2​​,C1​,C2​,…,Cs3​​,D1​,D2​,…,Ds4​​)。

kkksc03 有一个能力,他的左右两个大脑可以同时计算 2 道不同的题目,但是仅限于同一科。因此,kkksc03 必须一科一科的复习。

输入格式

本题包含 5 行数据:第 1 行,为四个正整数s1​,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背包

将时间分配到左右脑,使得两边的时间差最小。

#include<iostream>
using namespace std;
int sum,tot; 
int a[5],h[21],dp[2501];//科目、题目、时间 
int main()
{
	for(int i=1;i<=4;i++)
	{
		cin>>a[i];
	}
	for(int i=1;i<=4;i++)
	{
		sum=0;
		for(int j=1;j<=a[i];j++)
		{
			cin>>h[j];
			sum+=h[j];//计算总时间 
		}
		for(int j=1;j<=a[i];j++)
			for(int k=sum/2;k>=h[j];k--)//最慢时间为总时长一半 
				dp[k]=max(dp[k],dp[k-h[j]]+h[j]);//01背包 
		tot+=sum-dp[sum/2];//累加为另一边脑子 
		for(int j=1;j<=sum/2;j++) dp[j]=0;//清零 
	}
	cout<<tot;
	return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值