蓝桥31天|今天4道题Day2|C++

1.排他平方数

在这里插入图片描述
回溯+剪枝

#include <iostream>
#include <vector>
using namespace std;
const int N=10;
bool st[N];
vector<vector<int>>ans;
vector<int>num;

void backtracking(int level){
  if(level==6){
     long long tmp=0;
     bool flag=true;
     for(int i=0;i<6;i++){
       tmp*=10;
       tmp+=num[i];
     }
     tmp*=tmp;
     while(tmp){
       if(st[tmp%10]){
         flag=false;
         break;
       }
       tmp/=10;
     }
     
     if(flag)ans.push_back(num);
     return;
  }

  for(int i=0;i<=9;i++){
    if(!st[i]){
      st[i]=true;
      num.push_back(i);
      if(!(level==0&&i==0))backtracking(level+1);//排除最高位为0
      num.pop_back();
      st[i]=false;
    }
  }

}
int main()
{
  ans.clear();
  num.clear();
  backtracking(0);

  int s=0;
  for(int i=0;i<ans.size();i++){
     for(int j=0;j<ans[i].size();j++){
       s*=10;
       s+=ans[i][j];
     }
     if(s!=203879)break;
     else s=0;
  }
  printf("%d",s);
  
  

  return 0;
}

2.买不到的数目

在这里插入图片描述
法一:尽力分析
最大公约数d=(p,q)>1时没有解,所有互质的数都一定有解
eg.2 4 ->所有不是2的倍数的数都凑不出来

法二:打表找规律
打表代码

#include <iostream>
using namespace std;
bool dfs(int i,int p,int q){
  if(i==0)return true;
  if(i>=p&&dfs(i-p,p,q))return true;
  if(i>=q&&dfs(i-q,p,q))return true;
  return false;
}
int main()
{
  int p,q;
  scanf("%d%d",&p,&q);
  int res=0;
  for(int i=0;i<=1000;i++){
    if(!dfs(i,p,q))res=i;
  }
  printf("%d",res);
  return 0;
}

在这里插入图片描述

裴属定理
(p,q)=d
则一定存在2个整数使得ap+bq=d
如果(p,q)=q
必然存在ap+bq=1
要凑m
只要存在amp+bmp=m
(am-q)p+(bm+q)p=m

最后i=(p-1)(q-1)-1

#include <iostream>
using namespace std;
int main()
{
  int p,q;
  scanf("%d%d",&p,&q);
  
  printf("%d",(p-1)*(q-1)-1);
  return 0;
}

3. 回文日期

在这里插入图片描述

#include <iostream>
#include <vector>
using namespace std;
const int N=99999999;
int month[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
//判断日期是否合法
bool checkIsDate(int num){
    int yyyy=num/10000;
    int mm=num/100%100;
    if(mm>12||mm==00)return false;

    int dd=num%100;
    if(mm==2){
      if(yyyy%400==0||(yyyy%4==0&&yyyy%100!=0))month[2]=29;
      else month[2]=28;
    }
    if(dd>month[mm]||dd<=0)return false;
    return true; 
}
//判断是否是回文数
bool checkIsH(int num){
  vector<int>ans;
  for(int i=0;i<8;i++){
    ans.push_back(num%10);
    num/=10;
  }
  for(int i=0;i<4;i++){
    if(ans[i]!=ans[7-i])return false;
  }
  return true;
}
//判断是否是ABABBABA
bool checkIsAB(int num){
  vector<int>ans;
  for(int i=0;i<8;i++){
    ans.push_back(num%10);
    num/=10;
  }
  if(ans[0]==ans[1])return false;
  if(ans[0]!=ans[2]||ans[2]!=ans[5]||ans[5]!=ans[7])return false;
  if(ans[1]!=ans[3]||ans[3]!=ans[4]||ans[4]!=ans[6])return false;
  return true;
}

int main()
{
  int start;
  scanf("%d",&start);
  int ans1=0,ans2=0;
  bool flag1=true,flag2=true;
  for(int i=start+1;i<=N;i++){
      if(checkIsDate(i)){
        if(checkIsH(i)){
          if(flag1){
            ans1=i;
            flag1=false;
          }
          if(checkIsAB(i)){
            if(flag2){
            ans2=i;
            flag2=false;
            break;
          }
          }
        }
      }
  }
  printf("%d\n%d",ans1,ans2);

  return 0;
}

4.约瑟夫环

在这里插入图片描述
参考约瑟夫环问题详解
在这里插入图片描述
不难推得剩余最后一个元素时,序号为0
即J2(1) = 0------(1)
那么我们知道是这么得到的新的队列,那么也很容易知道怎么反推了:
在这里插入图片描述

反观如上的变化情况,都是减去一个q所以:
倒推这个最后剩下的0之前是序号几:
变回去的公式如下:old = (new + q) % n
剩余两个元素时(即0,1),删除序号为0,然后把0后一个序号变为0(即1变成0)
J2(2) = (J2(1) + 2) % 2 = 0------------(2)

剩余三个元素时(0,1,2),删除序号为2,然后把2后一个序号变为0(即0变成0)
J2(3) = (J2(2) + 2) % 3 = 2

剩余两个元素(0,1,2,3)时,删除序号为0,然后把0后一个序号变为0(即1变成0)
J2(4) = (J2(3) + 2) % 4 = 0


```cpp
#include<iostream>
#include<stdio.h>
using namespace std;

int f(int n,int m){
        if(n == 1){
                return 0; //这里返回下标,从0开始,只有一个元素就是剩余的元素0
        }
        else{
                return (f(n-1,m) + m) % n; //我们传入的n是总共多少个数
        }
}
int main(){
        int a,b;
        cin>>a>>b;
        cout<<f(a,b)+1<<endl;

		//或者,直接循环迭代,求出来的result如上
		// int result = 0;
    //     for(int i = 2;i <= a;i++){
    //             result = (result+b) %i;
    //     }
  
        return 0;
}

```

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值