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;
}
```