Problem A 空间
计组基础题:256MB=256 * 2^20 * 8 位
所以存放32位元素可以存放 256 * 1024 * 1024 * 8 / 32
ans: 67108864
送分题
Problem B 卡片
题目就是说0—9一共9种卡片,如果,每个3张可以排到10,那如果每个2021张可以排到多少?
我的思路:
第一遍做这个题时写了个3182,后来检查时又仔细读了一遍题发现不对,最后应该输出3181,差点儿错了,,,
code:
#include
using namespace std;
int num[10];
int del(int n)
{
while(n){
int index=n%10;
if(num[index]==0)return 0;
else num[index]--;
n/=10;
}
return 1;
}
int main()
{
for(int i=0;i<=9;i++){
num[i]=2021;
}
int n=1;
while(1){
int ff=del(n);
if(ff==0)break;
else n++;
}
printf("%d",n-1);
return 0;
}
ans:3181
Problem C直线
我的思路:
这题我错了,
我用的set
error code:
#include
using namespace std;
set<pair<double,double> > line_set;
int main()
{
int x1,y1,x2,y2;
for(x1=0;x1<20;x1++){
for(y1=0;y1<21;y1++){
for(x2=0;x2<20;x2++){
for(y2=0;y2<21;y2++){
if(x1!=x2&&y1!=y2){
double k=(y2-y1)*1.0/(x2-x1);
double b=y2-k*x2;
pair<double ,double > newline;
newline.first=k;
newline.second=b;
line_set.insert(newline);
}
}
}
}
}
printf("%d",line_set.size()+20+21);
return 0;
}
这样算出来是47753(error ans),知乎上有人说是40257,哎,蓝瘦~
贴一下正确解:
#include
using namespace std;
set<pair<double,double> > line_set;
int main()
{
int x1,y1,x2,y2;
for(x1=0;x1<20;x1++){
for(y1=0;y1<21;y1++){
for(x2=0;x2<20;x2++){
for(y2=0;y2<21;y2++){
if(x1!=x2&&y1!=y2){
double k=(y2-y1)*1.0/(x2-x1);
double b=(y2*(x2-x1)-(y2-y1)*x2)*1.0/(x2-x1);
//重点!这么写可以规避掉double炸精度问题
pair<double ,double> newline;
newline.first=k;
newline.second=b;
line_set.insert(newline);
}
}
}
}
}
printf("%d",line_set.size()+20+21);
return 0;
}
//40257
Problem D货物摆放
这个题没有办法,暴力吧,纯暴力还不行,必须优化!
我的思路:
由于要拆解成因子,拆解的三个因子(设为a,b,c),把a,b,c放到一个集合里s;
始终要a<=b<=c(不然超时!)
如果s.size()==1,ans+=1;//abc三者相等,为一种情况
如果s.size()==2,ans+=3;//abc三个有两个相等,则独立的哪个有三种放法
如果s.size()==3,ans+=6;//abc互不相等,全排列3 * 2 *1种
循环一定要两层,不要三层,必须使用sqrt降低复杂度
code:
#include
using namespace std;
typedef long long ll;
int main()
{
ll n=2021041820210418;
ll en1=sqrt(n);
ll ans=0;
for(ll a=1;a<=en1;a++){
if(n%a==0){
ll nn=n/a;
ll en2=sqrt(nn);
for(ll b=1;b<=en2;b++){
if(nn%b==0){
ll c=nn/b;
if(c>=b&&b>=a){
set<int> s;
s.insert(a);
s.insert(b);
s.insert(c);
if(s.size()==1)ans++;
else if(s.size()==2)ans+=3;
else if(s.size()==3)ans+=6;
}
}
}
}
}
printf("%lld",ans);
return 0;
}
ans:2430
Problem E路径
我的思路:
dijkstra即可,然而呢,我写的dijkstra调试了半天也不对,气急败坏之下又用的Floyd,三层for循环,等了10秒左右总算是跑出来了,,,
code:
#include
using namespace std;
typedef long long ll;
#define INF 999999999
int gcd(int a,int b){
if(b==0)return a;
else return gcd(b,a%b);
}
int M[2022][2022];
int main(){
for(int i=1;i<=2021;i++){
for(int j=1;j<=2021;j++){
if(i==j)M[i][j]=M[j][i]=0;
else if(abs(i-j)>21)M[i][j]=M[j][i]=INF;
else M[i][j]=M[j][i]=i*j/gcd(i,j);
}
}
for(int i=1;i<=2021;i++){
for(int j=i+1;j<=2021;j++){
for(int k=i;k<=j;k++){
if(M[i][k]!=INF&&M[k][j]!=INF&&(M[i][j]>M[i][k]+M[k][j])){
M[i][j]=M[j][i]=M[i][k]+M[k][j];
}
}
}
}
printf("%lld",M[1][2021]);
return 0;
}
ans:10266837
Problem F时间显示
题干说给出一个毫秒数,输出对应的hh:mm:ss
我的思路:
签到题
input_case1:
46800999
output_case1:
13:00:00
input_case2:
1618708103123
output_case2:
01:08:23
code:
#include
using namespace std;
typedef long long ll;
int main()
{
ll n;
scanf("%lld",&n);
n/=1000;
n%=(24*60*60);
int ss=n%60;
n/=60;
int mm=n%60;
n/=60;
int hh=n%60;
n/=60;
printf("%02d:%02d:%02d",hh,mm,ss);
return 0;
}
Problem G砝码称重
我的思路:
哎,万万没想到,第二个编程题直接来个dp,蓝桥杯啊,你变了啊,做往年的省赛b组题基本没遇到过dp,去年考了dp也只是在填空里考了,今年直接第二道编程考dp,哎,菜是原罪!
看了半天没思路,又看了看测试样例范围 50%的样例在1<=n<=15,果断dfs深搜骗分,,,
input_case:
3
1 4 6
output_case:
10
code:
#include
using namespace std;
int n;
int w[102];
int flag[102];
set<int> ans;
int ff=0;
void dfs(int sum1,int sum2){
if(sum1<sum2)return ;
else{
if(sum1>sum2){
ans.insert(sum1-sum2);
}
}
for(int i=1;i<=n;i++){
if(!flag[i]){
flag[i]=1;
dfs(sum1+w[i],sum2);
dfs(sum1,sum2+w[i]);
flag[i]=0;
}
}
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&w[i]);
}
dfs(0,0);
printf("%d",ans.size());
return 0;
}
贴一下正确解:
#include
using namespace std;
typedef long long ll;
int dp[102][100002];
int main()
{
int n;
scanf("%d",&n);
int w[n+1];
ll sum=0;
for(int i=1;i<=n;i++){
scanf("%d",&w[i]);
sum+=w[i];
}
for(int i=1;i<=n;i++){
for(int j=1;j<=sum;j++){
dp[i][j]=dp[i-1][j];
if(dp[i][j]==0){
if(w[i]>j)dp[i][j]=dp[i-1][w[i]-j];
if(w[i]==j)dp[i][j]=1;
if(w[i]<j)dp[i][j]=dp[i-1][j-w[i]];
}
}
}
ll ans=0;
for(int i=1;i<=sum;i++){
if(dp[n][i])ans++;
}
printf("%lld",ans);
return 0;
}
Problem H杨辉三角
我的思路:
没思路,,暴力骗分,,
组合数学问题
input_case:
6
output_case:
13
code:
#include
using namespace std;
int M[3001][3001];
int main(){
int n;
scanf("%d",&n);
for(int i=1;i<=n+1&&i<=3000;i++){
M[i][i]=1;
M[i][1]=1;
}
for(int i=3;i<=n+1&&i<=3000;i++){
for(int j=2;j<i;j++){
M[i][j]=M[i-1][j]+M[i-1][j-1];
}
}
int num=1;
for(int i=1;i<=n+1&&i<=3000;i++){
for(int j=1;j<=i;j++){
if(M[i][j]==n){
printf("%d",num);
return 0;
}else{
num++;
}
}
}
return 0;
}
Problem I双向排序
我的思路:
sort骗分,
刚开始以为用sort连30%的测试点都过不了(毕竟快排的最坏时间复杂度是平方阶的!),后来看了一下别人博客了解到,sort还是很牛的,毕竟是c++封装好的排序函数,记得之前学快排的时候,快排有好几种优化方案,什么三点取中法,等等,c++里面的sort是优化到极致的快排,很好用;
! (~ _ ~;)
n=4000,m=4000是不超时的,sort至少可以骗50%的分数。
input_case:
3 3
0 3
1 2
0 2
output_case:
3 1 2
code:
#include
using namespace std;
bool cmp1(int a,int b)//升序
{
return a<b;
}
bool cmp2(int a,int b)//降序
{
return a>b;
}
int main(){
int n,m;
scanf("%d %d",&n,&m);
int a[n+1];
for(int i=1;i<=n;i++){
a[i]=i;
}
int op,index;
for(int i=0;i<m;i++){
scanf("%d %d",&op,&index);
if(op==0){
sort(a+1,a+index+1,cmp2);
}else{
sort(a+index,a+n+1,cmp1);
}
}
for(int i=1;i<=n;i++){
printf("%d",a[i]);
if(i<n)printf(" ");
}
return 0;
}
Problem J括号序列
我的思路:
状压dp,蓝桥杯是真的变了,,,
又是dfs写的,骗分,,,
input_case:
((()
oupput_case:
5
code:
#include
using namespace std;
string s;
set<string> e;
int addNum;
char c;
bool isok()
{
stack<char> sta;
for(int i=0;i<s.size();i++){
if(s[i]=='('){
sta.push(s[i]);
}else{
if(sta.empty()||sta.top()!='(')return false;
else sta.pop();
}
}
if(sta.empty())return true;
else return false;
}
void dfs(int depth){
if(depth==addNum){
if(isok()){
e.insert(s);
}
}else{
for(int i=0;i<s.size();i++){
s.insert(s.begin()+i,c);
dfs(depth+1);
s.erase(s.begin()+i,s.begin()+i+1);
}
}
}
int main()
{
cin>>s;
int left=0,right=0;
for(int i=0;i<s.size();i++){
if(s[i]=='(')left++;
else right++;
}
if(left==right){
printf("0");
return 0;
}else{
if(left>right)c=')';
else c='(';
addNum=abs(left-right);
dfs(0);
printf("%d",e.size());
}
return 0;
}
总结:
填空对了4道,编程题只有第一个保证ac,其它4个均是dfs,,,暴力,,,骗分,,,
第一次参加蓝桥杯就突然难了,哎,菜是原罪啊!蓝桥杯是真的变了,加入了蝉联出题就硬气了,这几年来蓝桥杯也一直为人诟病,今年突然难了其实也是好事吧,希望蓝桥杯发展的越来越好吧。