2021-11-03计科ACM新生培训之暴力枚举

前言

今晚讲的是暴力枚举
相信大家都听懂了吧
暴力枚举只是一种思想,具体的问题还需要具体分析。
觉得自己掌握不太熟练的同学可以去洛谷上再多刷一些相关的题型
暴力枚举
下面开始今晚比赛的题解:

比赛题解

A 统计方形

在这里插入图片描述
首先,统计一个n*m的矩形里有多少个正方形,长方形。

要明确,正方形和长方形都是矩形,那么n*m的矩形里的

矩形数=正方形数+长方形数

明确这一点后,就可以一次求出二者了
在这里插入图片描述
在这里插入图片描述
如图,长为2宽为1的小长方形用〇来表示,那么

横向排列的就有 *(n-1)m 个

竖向排列的就有 n(m-1)* 个

证明:
∵ 矩形长不等于宽 ∴ 子矩形构成的矩阵的长宽是由原矩形长宽减去不同数而得 即(n-b)*(m-a) (a≠b)

#include<stdio.h>
long long n,m,rec,sqr;
int main() {
    
    scanf("%lld %lld", &n,&m);
    for(int i=0; i<n; i++)//循环,从n-0到n-(n-1)
        for(int j=0; j<m; j++) {//循环,从m-0到m-(m-1)
            if(i==j) sqr+=(n-i)*(m-j);//如果i==j,说明是正方形
            else rec+=(n-i)*(m-j);//如果不等说明是矩形
        }
    cout<<sqr<<" "<<rec<<endl;//输出
    printf("%lld %lld",sqr,rec);
    return 0;
}

B 分数拆分

在这里插入图片描述
暴力跑就完事了

#include<stdio.h>
int main()
{
   int t;
   scanf("%d",&t);
   while(t--)
   {
      int n;
      scanf("%d",&n);
      /*//已知K,用一个变量表示Y,则另一个数X可以用含Y和K的式子表示,
      避免用两个循环遍历,降低解题难度!
      */ 
      for(int i=n+1;i<=2*n;i++)
      {
         if((n*i)%(i-n)==0)
         printf("1/%d=1/%d+1/%d\n",n,(n*i)/(i-n),i);
      }
   }
   return 0;
}

C 约瑟夫问题

在这里插入图片描述
经典约瑟夫环问题,可以百度一下多了解了解

#include <stdio.h>
#include <string.h>
int vis[1005];//记录每一个数是否被输出 
int a[1000];//存数字 
int main() {
	int n, k;
	scanf("%d%d", &n, &k);//输入n和k 
	int cnt = 0;//记录遍历的数的个数 
	int sum = 0;//记录输出的数的个数 
	for (int i = 1; i <= n; i++) {
		a[i] = i;//初始化 
	}
	int i = 0;
	while (sum < n) {
		i++;
		if(i==n+1) {
			i=1;
		}
		if (vis[a[i]] == 1) {
			continue;
		}
		cnt++;
		if (cnt == k) {
			vis[a[i]] = 1;
			sum++;
			cnt = 0;
			printf("%d\n",a[i]);
		}
	}
	return 0;
}

D 暴力啥啊

在这里插入图片描述
AC代码:

#include <bits/stdc++.h>
using namespace std;
int v[1005][1005];
int main()
{
  int n, m;
  while (~scanf("%d%d", &n, &m))
  {
    int ans = 0;
    for (int i = 1; i <= n; i++)
      for (int j = 1; j <= n; j++)
        scanf("%d", &v[i][j]);
        //先存图 ,然后一直在图里面判断最大能炸多少
    for (int i = m; i <= n; i++)
    {
      for (int j = m; j <= n; j++)
      {
        int sum = 0;
        for (int ii = i - m + 1; ii <= i; ii++)
        {
          for (int jj = j - m + 1; jj <= j; jj++)
          {
            sum = sum + v[ii][jj];
          }
        }
        if (sum > ans)
          ans = sum;
      }
    }
    printf("%d\n", ans);
  }
  return 0;
}

E n!

在这里插入图片描述
本题的数据范围非常的大,光n就1e18了,更别说n的阶乘了,因此直接算出n的阶乘然后进行暴力枚举是不可能的,所以我们需要找规律,我们发现直接用n直接除以3后的商累加,除到不能被3整除为止答案与n的阶乘整除3相同。此题放在防AK的位置上是为了提醒大家,暴力有时候也不是直接上去暴力就能解决问题的,而是通过数学思想的优化,再进行暴力枚举。
FCX学长的解题思路:
在这里插入图片描述

AC代码:

#include <stdio.h>
int main()
{
    long long int n;
    scanf("%lld", &n);
    long long int t = 0;
    while (n / 3)
    {
        n /= 3;
        t += n;
    }
    printf("%lld\n", t);
    return 0;
}

F Kalevitch and Chess

在这里插入图片描述
解题思路:只要这一行有大B就要刷,如果刷了16次,去重刷8次就够了。
AC代码:

#include<stdio.h>
char a[10][10];
int main()
{
  int i, j;
  for (i = 0; i < 8; i++)
  {
      scanf("%s", a[i]);//先存图
  }
  int ans = 0;
  for (int i = 0; i < 8; i++)//横向遍历
  {
    bool f = 1;//每次遍历新的一行的时候 标记初始化
    for (int j = 0; j < 8; j++)
    {
      if (a[i][j] != 'B')//如果等于W就不用粉刷因此让标记等于0
        f = 0;
    }
    if (f)
      ans++;
  }
  //同理的纵向遍历
  for (int i = 0; i < 8; i++)
  {
    bool f = 1;
    for (int j = 0; j < 8; j++)
    {
      if (a[j][i] != 'B')//注意是a[j][i]!!!!
        f = 0;
    }
    if (f)
      ans++;
  }
  if (ans == 16)//去除
    ans = 8;
  printf("%d\n", ans);
  return 0;
}```

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值