day12 2023/02/12
今天虽然休息,就搞几道蓝桥杯题目(主要是数学+简单dp)
一、蚂蚁感冒(第五届蓝桥杯省赛C++A/B组)
考查知识点:脑筋急转弯
性质:1)掉头等价于穿过
2)第一个蚂蚁向右走的情况:右边向右走和左边向左走的蚂蚁都是安全的,右边向左走的蚂蚁一定感染,左边向右的蚂蚁则需要分情况讨论:
1.右边存在向左走,则必然被感染
2.右边不存在向左走,则必然不会被感染
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <cmath>
using namespace std;
const int N=51;
int n;
int a[N];
int main()
{
int cnt=0;
cin>>n;
for(int i=0;i<n;i++)
cin>>a[i];
int left=0,right=0;
for(int i=0;i<n;i++)
{
//记录右边向左走的蚂蚁的数量
if(abs(a[i])>abs(a[0])&&a[i]<0)
right++;
//记录左边向右走的蚂蚁的数量
if(abs(a[i])<abs(a[0])&&a[i]>0)
left++;
}
if(a[0]>0)
{
if(right>0)
cnt=left+right+1;
else if(right==0)
cnt=1;
}
if(a[0]<0)
{
if(left>0)
cnt=left+right+1;
else if(left==0)
cnt=1;
}
cout<<cnt<<endl;
return 0;
}
二、饮料换购(第六届蓝桥杯C++A组)
方法:模拟过程并且提炼出代码
代码如下:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int n;
int main()
{
cin>>n;
int res=n;
while(n>=3)
{
res+=n/3;
n=n/3+n%3;
}
cout<<res<<endl;
return 0;
}
如何去求上取整?
(a/b)的上取整等于(a+b-1)/b的下取整
从集合方式理解dp问题
动态规划:
1)状态表示(化零为整) f [ i , j ]:
集合(所有只从前 i 个物品中选,且总体积不超过 j 的所有方案的集合)
属性(Min/Max/Count)
2)状态计算(化整为零)
集合的划分(划分依据是找最后一个不同点)
三、01背包问题(组合模型)
分析如下:
代码如下:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=1010;
int n,m;
int v[N],w[N];
int f[N][N];
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
cin>>v[i]>>w[i];
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(j>=v[i])
f[i][j]=max(f[i-1][j],f[i-1][j-v[i]]+w[i]);
else
f[i][j]=f[i-1][j];
}
}
cout<<f[n][m]<<endl;
return 0;
}
四、摘花生(路线模型)
分析如下:
代码如下:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
const int N=110;
int T;
int r,c;
int a[N][N],f[N][N];
int main()
{
cin>>T;
while(T--)
{
cin>>r>>c;
for(int i=1;i<=r;i++)
{
for(int j=1;j<=c;j++)
{
cin>>a[i][j];
}
}
for(int i=1;i<=r;i++)
{
for(int j=1;j<=c;j++)
{
f[i][j]=max(f[i][j-1],f[i-1][j])+a[i][j];
}
}
cout<<f[r][c]<<endl;
}
return 0;
}
五、最大上升子序列
分析如下:
代码如下:
#include <iostream>
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
const int N=1010;
int a[N],f[N];
int n;
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i];
int res=0;
for(int i=1;i<=n;i++)
{
f[i]=1;
for(int j=1;j<i;j++)
{
if(a[i]>a[j])
f[i]=max(f[i],f[j]+1);
}
res=max(res,f[i]);
}
cout<<res<<endl;
return 0;
}
六、地宫取宝(第五届蓝桥杯省赛C++A组)
分析如下:
代码如下:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N=51;
const int MOD=1000000007;
int n,m,k;
int w[N][N],f[N][N][13][14];
int main()
{
cin>>n>>m>>k;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
cin>>w[i][j];
w[i][j]++;
}
}
f[1][1][1][w[1][1]]=1;
f[1][1][0][0]=1;//初始化f
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(i==1&&j==1) continue;
for(int u=0;u<=k;u++)
{
for(int v=0;v<=13;v++)
{
int& val=f[i][j][u][v];
val=(val+f[i-1][j][u][v])%MOD;
val=(val+f[i][j-1][u][v])%MOD;
if(u>0&&v==w[i][j])
{
for(int c=0;c<v;c++)
{
val=(val+f[i-1][j][u-1][c])%MOD;
val=(val+f[i][j-1][u-1][c])%MOD;
}
}
}
}
}
}
int res=0;
for(int i=0;i<=13;i++)
res=(res+f[n][m][k][i])%MOD;
cout<<res<<endl;
return 0;
}
七、波动数列(第五届蓝桥杯C++A组)
分析如下:
代码如下:
#include <iostream>
using namespace std;
const int N=1010;
const int mod=100000007;
int f[N][N];
int n,s,a,b;
int get_mod(int a,int b)
{
return (a%b+b)%b;
}
int main()
{
cin>>n>>s>>a>>b;
f[0][0]=1;
for(int i=1;i<n;i++)
{
for(int j=0;j<n;j++)
{
f[i][j]=(f[i-1][get_mod(j-a*i,n)]+f[i-1][get_mod(j+b*i,n)])%mod;
}
}
cout<<f[n-1][get_mod(s,n)]<<endl;
return 0;
}
第四章 枚举、模拟与排序
1.连号区间数(maxv-minv==b-a)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=10010;
const int INF=100000000;
int n,a[N];
int main()
{
cin>>n;
for(int i=0;i<n;i++)
cin>>a[i];
int res=0;
for(int i=0;i<n;i++)
{
int minv=INF,maxv=-INF;
for(int j=i;j<n;j++)
{
minv=min(minv,a[j]);
maxv=max(maxv,a[j]);
if(maxv-minv==j-i)
res++;
}
}
cout<<res<<endl;
return 0;
}
2.递增三元组(前缀和)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N=100010;
int n;
int a[N],b[N],c[N];
int as[N],cs[N];
int s[N],cnt[N];
int main()
{
cin>>n;
for(int i=0;i<n;i++)
cin>>a[i],a[i]++;
for(int i=0;i<n;i++)
cin>>b[i],b[i]++;
for(int i=0;i<n;i++)
cin>>c[i],c[i]++;
for(int i=0;i<n;i++)
cnt[a[i]]++;
for(int i=1;i<N;i++)
s[i]=s[i-1]+cnt[i];
for(int i=0;i<n;i++)
as[i]=s[b[i]-1];
memset(cnt,0,sizeof cnt);
memset(s,0,sizeof s);
for(int i=0;i<n;i++)
cnt[c[i]]++;
for(int i=1;i<N;i++)
s[i]=s[i-1]+cnt[i];
for(int i=0;i<n;i++)
cs[i]=s[N-1]-s[b[i]];
LL res=0;
for(int i=0;i<n;i++)
res+=(LL)as[i]*cs[i];
cout<<res<<endl;
return 0;
}
3.特别数的和(第十届蓝桥杯C++B组)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=10010;
int n;
int main()
{
cin>>n;
int sum=0;
for(int i=1;i<=n;i++)
{
int x=i;
while(x)
{
int t=x%10;
x/=10;
if(t==2||t==0||t==1||t==9)
{
sum+=i;
break;
}
}
}
cout<<sum<<endl;
return 0;
}
4.错误票据(第四届蓝桥杯C++A组)
5.回文日期