1.纯质数
可参考
数论模板-素数筛、约数、欧拉函数
法一:试除法
时间复杂度:O(nsqrt(n))
超时
i<n/i
法二:最普通的筛法
依次筛去所有数的倍数
时间复杂度 O(nlogn)
超时
#include <iostream>
#include <cstring>
using namespace std;
const int N=20210605,M=N+10;
bool st[M];
bool check(int num){
// for(int i=num;i>0;i/=10){
// if(st[i%10])return false;
// }
while(num){
if(st[num%10])return false;
num/=10;
}
return true;
}
int main()
{
int ans=0;
st[0]=true;
st[1]=true;
for(int i=2;i<=N;i++){
if(!st[i]&&check(i))ans++;
for(int j=i*2;j<=N;j+=i){
st[j]=true;
}
}
printf("%d",ans);
return 0;
}
法三:诶式筛法
依次筛去所有质数的倍数
时间复杂度 O(nloglogn)
#include <iostream>
#include <cstring>
using namespace std;
const int N=20210605,M=N+10;
bool st[M];
bool check(int num){
// for(int i=num;i>0;i/=10){
// if(st[i%10])return false;
// }
while(num){
if(st[num%10])return false;
num/=10;
}
return true;
}
int main()
{
int ans=0;
st[0]=true;
st[1]=true;
for(int i=2;i<=N;i++){
if(!st[i]){
if(check(i))ans++;
for(int j=i*2;j<=N;j+=i){
st[j]=true;
}
}
}
printf("%d",ans);
return 0;
}
法四:线性筛法
合数只会被最小质因子筛掉,每个数只会被筛一次,所以是线性的
时间复杂度 O(n)
最优
#include <iostream>
#include <cstring>
using namespace std;
const int N=20210605,M=N+10;
bool st[M];
int prime[M];
int cnt;
bool check(int num){
// for(int i=num;i>0;i/=10){
// if(st[i%10])return false;
// }
while(num){
if(st[num%10])return false;
num/=10;
}
return true;
}
int main()
{
int ans=0;
st[0]=true;
st[1]=true;
for(int i=2;i<=N;i++){
if(!st[i]){
if(check(i))ans++;
prime[cnt++]=i;
}
for(int j=0;prime[j]<N/i;j++){
st[prime[j]*i]=true;
if(i%prime[j]==0)break;
}
}
printf("%d",ans);
return 0;
}
2.最少砝码
借鉴2021 蓝桥杯:最少砝码 == 平衡三进制/贪心
平衡三进制
法一:贪心(找规律)
#include <iostream>
using namespace std;
int main()
{
int n;
scanf("%d",&n);
int t=1;
int ans=0;
while(n>0){
n-=t;
t*=3;
ans++;
}
printf("%d",ans);
return 0;
}
法二:平衡三进制
将标准三进制转换为平衡三进制{ − 1 , 0 , 1 } ,该位为-1放左边,为1放右边,为0不放。
因此本题也可以这样做:
即,对输入的 n 求平衡三进制数,该数的位数即为答案
#include <iostream>
#include <vector>
using namespace std;
int main()
{
int n;
cin>>n;
vector<int>list;
while(n){
list.push_back(n%3);
n/=3;
}
for(int i=0;i<list.size();i++){
if(list[i]==2){
list[i]=-1;
if(i+1<list.size())list[i+1]+=1;
else list.push_back(1);
}else if(list[i]==3){
list[i]=0;
if(i+1<list.size())list[i+1]=1;
else list.push_back(1);
}
}
printf("%d",list.size());
return 0;
}
3.灌溉
感谢@不排不改同学指出map[x][y]经过后要标记
#include <iostream>
#include <vector>
using namespace std;
const int N=110;
typedef pair<int,int>PII;
int dx[4]={-1,0,1,0},dy[4]={0,1,0,-1};
bool map[N][N];//判断是否已被灌溉
int main()
{
int n,m;
int t,r,c;
vector<PII>pipe;
int k;
scanf("%d%d",&n,&m);
scanf("%d",&t);
for(int i=0;i<t;i++){
scanf("%d%d",&r,&c);
pipe.push_back({r,c});
map[r][c]=true;//有出水管的位置可以被认为已经灌溉好
}
scanf("%d",&k);
while(k--){
int len=pipe.size();
for(int i=0;i<len;i++){
auto pos=pipe[i];
for(int j=0;j<4;j++){
int x=pos.first+dx[j];
int y=pos.second+dy[j];
if(!map[x][y]&&x>=1&&x<=n&&y>=1&&y<=m){
pipe.push_back({x,y});
map[x][y]=true;
}
}
}
}
printf("%d",pipe.size());
return 0;
}