蓝桥杯-2017年省赛部分题解

K倍区间
在这里插入图片描述
题解及代码

/*求区间[l,r]的和是k的倍数的个数。求区间和,我们可以通过前缀和来求出。我们规定sum[i]表示第1个元素到第i个元素的和。
那么sum[r] - sum[l-1]就是区间[l,r]的和。区间[l,r]的和是k的倍数即(sum[r] - sum[l-1])%k == 0 即sum[r]%k == sum[l-1]%k
那么,我们求出每个前缀和,在求的过程中取模,两个相等的前缀和就能组成一个k倍区间。
我们用一个数组cnt[i]表示当前位置之前,前缀和取模后等于i的个数。
如果当前前缀和sum%k==i,那么,当前位置与之前所有(sum%k==i)都能匹配,所有总个数要加上cnt[i].
*/
#include<bits/stdc++.h>
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
const double eps=3e-8;
const int maxn=100005;
int pre[maxn];
int cnt[maxn];
int n,k;
int a[maxn];
int main(){
    freopen("1.txt","r",stdin);
    cin>>n>>k;
    mem(pre,0);
    mem(cnt,0);
    int sum=0;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        pre[i]=(pre[i-1]+a[i])%k;
        sum+=cnt[pre[i]];
        cnt[pre[i]]++;
    }
    cout<<sum+cnt[0]<<endl;//要记得加上本身一个数字就能被整除的数
    return 0;
}

承压计数

X星球的高科技实验室中整齐地堆放着某批珍贵金属原料。
每块金属原料的外形、尺寸完全一致,但重量不同。
金属材料被严格地堆放成金字塔形。
                             7 
                            5 8 
                           7 8 8 
                          9 2 7 2 
                         8 1 4 9 1 
                        8 1 8 8 4 1 
                       7 9 6 1 4 5 4 
                      5 6 5 5 6 9 5 6 
                     5 5 4 7 9 3 5 5 1 
                    7 5 7 9 7 4 7 3 3 1 
                   4 6 4 5 5 8 8 3 2 4 3 
                  1 1 3 3 1 6 6 5 5 4 4 2 
                 9 9 9 2 1 9 1 9 2 9 5 7 9 
                4 3 3 7 7 9 3 6 1 3 8 8 3 7 
               3 6 8 1 5 3 9 5 8 3 8 1 8 3 3 
              8 3 2 3 3 5 5 8 5 4 2 8 6 7 6 9 
             8 1 8 1 8 4 6 2 2 1 7 9 4 2 3 3 4 
            2 8 4 2 2 9 9 2 8 3 4 9 6 3 9 4 6 9 
           7 9 7 4 9 7 6 6 2 8 9 4 1 8 1 7 2 1 6 
          9 2 8 6 4 2 7 9 5 4 1 2 5 1 7 3 9 8 3 3 
         5 2 1 6 7 9 3 2 8 9 5 5 6 6 6 2 1 8 7 9 9 
        6 7 1 8 8 7 5 3 6 5 4 7 3 4 6 7 8 1 3 2 7 4 
       2 2 6 3 5 3 4 9 2 4 5 7 6 6 3 2 7 2 4 8 5 5 4 
      7 4 4 5 8 3 3 8 1 8 6 3 2 1 6 2 6 4 6 3 8 2 9 6 
     1 2 4 1 3 3 5 3 4 9 6 3 8 6 5 9 1 5 3 2 6 8 8 5 3 
    2 2 7 9 3 3 2 8 6 9 8 4 4 9 5 8 2 6 3 4 8 4 9 3 8 8 
   7 7 7 9 7 5 2 7 9 2 5 1 9 2 6 5 3 9 3 5 7 3 5 4 2 8 9 
  7 7 6 6 8 7 5 5 8 2 4 7 7 4 7 2 6 9 2 1 8 2 9 8 5 7 3 6 
 5 9 4 5 5 7 5 5 6 3 5 3 9 5 8 9 5 4 1 2 6 1 4 3 5 3 2 4 1 
X X X X X X X X X X X X X X X X X X X X X X X X X X X X X X 
其中的数字代表金属块的重量(计量单位较大)。
最下一层的X代表30台极高精度的电子秤。
假设每块原料的重量都十分精确地平均落在下方的两个金属块上,
最后,所有的金属块的重量都严格精确地平分落在最底层的电子秤上。
电子秤的计量单位很小,所以显示的数字很大。
工作人员发现,其中读数最小的电子秤的示数为:2086458231
请你推算出:读数最大的电子秤的示数为多少?

处理完的数据
7 
5 8 
7 8 8 
9 2 7 2 
8 1 4 9 1 
8 1 8 8 4 1 
7 9 6 1 4 5 4 
5 6 5 5 6 9 5 6 
5 5 4 7 9 3 5 5 1 
7 5 7 9 7 4 7 3 3 1 
4 6 4 5 5 8 8 3 2 4 3 
1 1 3 3 1 6 6 5 5 4 4 2 
9 9 9 2 1 9 1 9 2 9 5 7 9 
4 3 3 7 7 9 3 6 1 3 8 8 3 7 
3 6 8 1 5 3 9 5 8 3 8 1 8 3 3 
8 3 2 3 3 5 5 8 5 4 2 8 6 7 6 9 
8 1 8 1 8 4 6 2 2 1 7 9 4 2 3 3 4 
2 8 4 2 2 9 9 2 8 3 4 9 6 3 9 4 6 9 
7 9 7 4 9 7 6 6 2 8 9 4 1 8 1 7 2 1 6 
9 2 8 6 4 2 7 9 5 4 1 2 5 1 7 3 9 8 3 3 
5 2 1 6 7 9 3 2 8 9 5 5 6 6 6 2 1 8 7 9 9 
6 7 1 8 8 7 5 3 6 5 4 7 3 4 6 7 8 1 3 2 7 4 
2 2 6 3 5 3 4 9 2 4 5 7 6 6 3 2 7 2 4 8 5 5 4 
7 4 4 5 8 3 3 8 1 8 6 3 2 1 6 2 6 4 6 3 8 2 9 6 
1 2 4 1 3 3 5 3 4 9 6 3 8 6 5 9 1 5 3 2 6 8 8 5 3 
2 2 7 9 3 3 2 8 6 9 8 4 4 9 5 8 2 6 3 4 8 4 9 3 8 8 
7 7 7 9 7 5 2 7 9 2 5 1 9 2 6 5 3 9 3 5 7 3 5 4 2 8 9 
7 7 6 6 8 7 5 5 8 2 4 7 7 4 7 2 6 9 2 1 8 2 9 8 5 7 3 6 
5 9 4 5 5 7 5 5 6 3 5 3 9 5 8 9 5 4 1 2 6 1 4 3 5 3 2 4 1 

题解及代码

/*
其实就是类似杨辉三角
*/
double dp[40][40];
int main(){
    freopen("1.txt","r",stdin);
    for(int i=0;i<40;i++){
        for(int j=0;j<40;j++)dp[i][j]=0;
    }
    for(int i=1;i<30;i++){
        for(int j=1;j<=i;j++)cin>>dp[i][j];
    }
    for(int i=2;i<=30;i++){
        for(int j=1;j<=i;j++){
            dp[i][j]+=dp[i-1][j-1]/2+dp[i-1][j]/2;
        }
    }
    double y=mod;
    double ma=0;
    for(int i=1;i<=30;i++){
        y=min(y,dp[30][i]);
        ma=max(ma,dp[30][i]);
    }
    cout<<y<<" "<<ma<<endl;
    double ans=ma*(2086458231.0/y);
    printf("%lf\n",ans);
    return 0;
}

分巧克力

    儿童节那天有K位小朋友到小明家做客。小明拿出了珍藏的巧克力招待小朋友们。
    小明一共有N块巧克力,其中第i块是Hi x Wi的方格组成的长方形。
    为了公平起见,小明需要从这 N 块巧克力中切出K块巧克力分给小朋友们。切出的巧克力需要满足:
    1. 形状是正方形,边长是整数  
    2. 大小相同  
例如一块6x5的巧克力可以切出6块2x2的巧克力或者2块3x3的巧克力。
当然小朋友们都希望得到的巧克力尽可能大,你能帮小Hi计算出最大的边长是多少么?
输入
第一行包含两个整数N和K。(1 <= N, K <= 100000)  
以下N行每行包含两个整数Hi和Wi。(1 <= Hi, Wi <= 100000) 
输入保证每位小朋友至少能获得一块1x1的巧克力。   
输出
输出切出的正方形巧克力最大可能的边长。
样例输入:
2 10  
6 5  
5 6  
样例输出:
2
资源约定:
峰值内存消耗(含虚拟机) < 256M
CPU消耗  < 1000ms

题解及代码

#include<bits/stdc++.h>
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
const double eps=3e-8;
const int mod=3e9+7;
const int maxn=1e5+7;
//一开始以为dp,后来发现数据范围太大了
//看题解介绍是二分模板题。。。
//二分边长,然后去判断数量够不够
struct node{
    int h,w;
    node(int H,int W):h(H),w(W){}
    node(){}
};
node a[maxn];
int n,k;
bool judge(int m){
    int sum=0;
    for(int i=0;i<n;i++){
        int x=a[i].h/m;
        int y=a[i].w/m;
        sum+=x*y;
    }
    return sum>=k;
}
int solve(){
    int l=1,r=100001,mid;
    int ans=-1;
    while(l<r){
        mid=(l+r)/2;
        if(judge(mid)){
            ans=mid;
            //cout<<"mid="<<mid<<endl;
            l=mid+1;
        }
        else r=mid;
    }
    return ans;
}
int main(){
    freopen("1.txt","r",stdin);
    cin>>n>>k;
    for(int i=0;i<n;i++){
        cin>>a[i].h>>a[i].w;
    }
    cout<<solve()<<endl;
    return 0;
}

包子凑数
在这里插入图片描述
题解及代码

#include<bits/stdc++.h>
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
const int maxn=105;
const int mod=maxn*maxn+20;
int a[maxn];
bool vis[maxn*(maxn+1)];
int main(){
    int n;
    cin>>n;
    int gcdd=0;
    mem(vis,0);
    for(int i=0;i<n;i++){
        cin>>a[i];
        vis[a[i]]=1;
        gcdd=__gcd(a[i],gcdd);
    }
    if(gcdd!=1)printf("INF\n");
    else{
    //我觉得可以认为是筛法,也可以认为是完全背包
        for(int i=0;i<n;i++){
            for(int j=0;j+a[i]<mod;j++){
                if(vis[j])vis[j+a[i]]=1;
            }
        }
        int ans=0;
        for(int j=mod-1;j>0;j--){
            if(!vis[j])ans++;
        }
        printf("%d\n",ans);
    }
    return 0;
}

日期问题
在这里插入图片描述
题解及代码

/*
写一个日期的类会好很多
*/
#include<bits/stdc++.h>
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
const double eps=3e-8;
const int maxn=100005;
//1 3 5 7 8 10 12   上半年单数,下半年双数
//Date结构体!!!
int mon_day[]={0,31,28,31,30,31,30,31,31,30,31,30,31};
struct Date{
    int year,month,day;
    Date(int y,int m,int d):year(y),month(m),day(d){}
    Date(){}
    bool isLeap(){
        return (year%400==0)||(year%4==0&&year%100!=0);
    }
    bool vaild(){
        if(year<1960||year>2059)return false;
        if(month<1||month>12)return false;
        if(day<1)return false;
        if(isLeap()){
            if(month==2)return day<=mon_day[month]+1;
            return day<=mon_day[month];
        }
        else  return day<=mon_day[month];
    }
    bool operator <(const Date b)const{
        if(year==b.year){
            if(month==b.month){
                return day<b.day;
            }
            return month<b.month;
        }
        return year<b.year;
    }
    void printDate(){
        printf("%d-%02d-%02d\n",year,month,day);
    }
};
set<Date>que;
void insertDa(int y,int m,int d){
    Date dd(y,m,d);
    if(dd.vaild()){
        que.insert(dd);
    }
}
void solve(){
    int y,m,d;
    scanf("%d/%d/%d",&y,&m,&d);
    int y1=1900;
    int y2=2000;
    //年y月m日d
    insertDa(y+y1,m,d);
    insertDa(y+y2,m,d);
    //月y日m年d
    insertDa(d+y1,y,m);
    insertDa(d+y2,y,m);
    //日y月m年d
    insertDa(d+y1,m,y);
    insertDa(d+y2,m,y);

    for(auto it:que){
        it.printDate();
    }
}
int main(){
    solve();
    return 0;
}

方格分割

标题:方格分割
6x6的方格,沿着格子的边线剪开成两部分。
要求这两部分的形状完全相同。
如图:p1.png, p2.png, p3.png 就是可行的分割法。
试计算:
包括这3种分法在内,一共有多少种不同的分割方法。
注意:旋转对称的属于同一种分割法。
请提交该整数,不要填写任何多余的内容或说明文字。

在这里插入图片描述
题解及代码

#include<bits/stdc++.h>
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
const double eps=3e-8;
int sum=0;
bool vis[10][10];
int d[4][2]={{0,1},{0,-1},{1,0},{-1,0}};
///边线是交汇点才是标号处,格子不是标号
void dfs(int x,int y){
    if(x==0||y==0||x==6||y==6){//线走到边界就没有其他平移的必要了,对格子数不产生影响
        sum++;
        return;///代表结束递归!!!!
    }
    for(int i=0;i<4;i++){
        int xx=x+d[i][0];
        int yy=y+d[i][1];
        if(!vis[xx][yy]){
            vis[xx][yy]=1;
            vis[6-xx][6-yy]=1;
            dfs(xx,yy);
            vis[xx][yy]=0;
            vis[6-xx][6-yy]=0;
        }
    }
}
int main(){
    sum=0;
    mem(vis,0);
    vis[3][3]=1;
    dfs(3,3);
    cout<<sum/4<<endl;//旋转对称属于一种方案(4个方向嘛)
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值