2017省賽藍橋杯B組

Annaprincess發表於2024-04-04

2017省賽藍橋杯B組

5.購物單

檢視程式碼

檢視程式碼

 #include <iostream>
using namespace std;
int main()
{
  // 請在此輸入您的程式碼
  double sum = 180.90*0.88+10.25*0.65+56.14*0.9+104.65*0.9+100.30*0.88+297.15*0.5+26.75*0.65+130.62*0.5+240.28*0.58+270.62*0.8+115.87*0.88+247.34*0.95+73.21*0.9+101.00*0.5+79.54*0.5+278.44*0.7+199.26*0.5+12.97*0.9+166.30*0.78+125.50*0.58+84.98*0.9+113.35*0.68+166.57*0.5+42.56*0.9+81.90*0.95+131.78*0.8+255.89*0.78+109.17*0.9+146.69*0.68+139.33*0.65+141.16*0.78+154.74*0.8+59.42*0.8+85.44*0.68+293.70*0.88+261.79*0.65+11.30*0.88+268.27*0.58+128.29*0.88+251.03*0.8+208.39*0.75+128.88*0.75+62.06*0.9+225.87*0.75+12.89*0.75+34.28*0.75+62.16*0.58+129.12*0.5+218.37*0.5+289.69*0.8;
  int a = (int)(sum+100)/100*100;
  printf("%d",a);
  return 0;
}

考點:將資料輸入進去看有幾個100-->52個100

答案:5200

6.等差素數列

#include <bits/stdc++.h>
using namespace std;
typedef long long int ll;
const int N=5000;
ll a[N];
set<ll>all;
//判素數
bool is_prime(ll t){
for(int i=2;i*i<=t;i++){
if(t%i==0)return false;
}
return true;
}
找最小公差等差素數列
ll f(){
for(int i=0;i<5000;i++){//列舉首項
ll fir=a[i];
//列舉公差
for(int del=2;del<a[4999]-a[fir];del++){//公差不可能大於最大項-當前首項
int m=fir;
for(int j=1;j<10;j++){//列舉項數(要找10項所以從首項往後9項)
m+=del;
if(all.find(m)==all.end())break;//找不到
if(j==9)return del;//找到了,因為加了9項公差如果找不到早返回!
}
}
}
return -1;
}
int main()
{
all.insert(2);
all.insert(3);
a[0]=2;
a[1]=3;
int id=2;
ll h=5;
//先打表a素數列
while(id<5000){
if(is_prime(h)){
all.insert(h);
a[id++]=h;
}
h++;
}
cout<<f();
// 請在此輸入您的程式碼
return 0;
}
注意:
不能用
因為lower_bound找大於等於不能嚴格控制等於
lower_bound(a,a+n,m)==n-->這個表示找不到m因為找到最後一個下標n-1的後一個即n

set的用法

set<int> q; //以int型為例 預設按鍵值升序
set<int,greater<int>> p; //降序排列
int x;
q.insert(x); //將x插入q中
q.erase(x); //刪除q中的x元素,返回0或1,0表示set中不存在x
q.clear(); //清空q
q.empty(); //判斷q是否為空,若是返回1,否則返回0
q.size(); //返回q中元素的個數
q.find(x); //在q中查詢x,返回x的迭代器,若x不存在,則返回指向q尾部的迭代器即 q.end()
q.lower_bound(x); //返回一個迭代器,指向第一個鍵值不小於x的元素
q.upper_bound(x); //返回一個迭代器,指向第一個鍵值大於x的元素
q.rend(); //返回第一個元素的的前一個元素迭代器
q.begin(); //返回指向q中第一個元素的迭代器
q.end(); //返回指向q最後一個元素下一個位置的迭代器
q.rbegin(); //返回最後一個元素

7.承壓計算

演算法:動態規劃(類似於數字三角形)

#include<bits/stdc++.h>
using namespace std;
//29行有數
const int N=35;
int a[N][N];
double dp[N][N];
int main(){
for(int i=1;i<=29;i++){
for(int j=1;j<=i;j++){
cin>>a[i][j];
}
}
dp[1][1]=a[1][1];
for(int i=2;i<=30;i++ ){
for(int j=1;j<=i;j++){
dp[i][j]=a[i][j]+0.5*(dp[i-1][j]+dp[i-1][j-1]);
}
}
double m=dp[30][1];
double s=dp[30][1];
for(int i=2;i<=30;i++){
if(m<dp[30][i]){
m=dp[30][i];
}
if(s>dp[30][i]){
s=dp[30][i];
}
}
long long int t=m*(2086458231*1.0/s);//注意精度問題,如果用double當位數太多會出現e的多少次方-->科學計數法!
cout<<t;
return 0;
}

4.方格分割

考點:dfs

#include<bits/stdc++.h>
using namespace std;
int vis[10][10];// 標記是否訪問過
int ans;
int dx[4] ={-1,0,0,1};//行標 變化(上左右下)
int dy[4] ={0,-1,1,0}; //列標變化(上左右下)
void dfs(int a,int b){
//(1)到邊界說明該路線結束ans++
if(a==0||a==6||b==0||b==6){
ans++;
return ;
}
//(2)訪問該點
vis[a][b]=1;
vis[6-a][6-b]=1;//剪一刀對稱的那邊也剪了
//(3)四個方向走
for(int i=0;i<4;i++){
//當前點四個方向走
int nx=a+dx[i];
int ny=b+dy[i];
if(nx<0||nx>6||ny<0||ny>6){
//超過邊界
continue;
}
if(!vis[nx][ny]){
//沒訪問過
dfs(nx,ny) ;
}
}
//恢復現場
vis[a][b]=0;
vis[6-a][6-b]=0;
}
int main()
{
dfs(3,3);//從中心點(3,3)開始搜,因為剪是中心對稱剪!
cout<<ans/4; //注意旋轉對稱算一次,所以四個方向除以4.
return 0;
}

題目:取數位

考察:遞迴

#include<bits/stdc++.h>
using namespace std;
//計算位數
int len(int x){
if(x<10)return 1;//1位數
return len(x/10) +1;
}
//計算第k位數
int f(int x,int k ){
if(len(x)-k==0)return x%10;//末位數
return f(x/10,k);//答案
}
int main(){
int x=23574;
cout<<f(x,3);
return 0;
}

題目:最大公共子串

#include <stdio.h>
#include <string.h>
#define N 256
int f(const char* s1, const char* s2)
{
int a[N][N];
int len1 = strlen(s1);
int len2 = strlen(s2);
int i,j;
memset(a,0,sizeof(int)*N*N);
int max = 0;
for(i=1; i<=len1; i++){
for(j=1; j<=len2; j++){
if(s1[i-1]==s2[j-1]) {
a[i][j] = __________________________; //填空
if(a[i][j] > max) max = a[i][j];
}
}
}
return max;
}
int main()
{
printf("%d\n", f("abcdkkk", "baabcdadabc"));
return 0;
}

答案: a[i][j] =a[i-1][j-1]+1;

考動態規劃轉移方程->意思是公共子串到s1的第i位和s2的第j位匹配的長度為公共子串到s1的第i-1位和s2的第j-1位的長度+1

2.日期問題

#include<bits/stdc++.h>
using namespace std;
struct sj{
int n;
int y;
int r;
}a[3];
//比較函式
bool com(sj p,sj q){
if(p.n!=q.n)return p.n<q.n;//早的放前面
if(p.y!=q.y)return p.y<q.y;
return p.r<q.r;
}
int year;
bool ir() {
if((year%4==0&&year%100!=0)||(year%400==0))return true;
return false;
}
int cn(int h){
if(h>=0&&h<=59)year=2000+h;
else{
year=1900+h;
}
return year;
}
//月
bool cy(int m){
if(m>=1&&m<=12)return true;
return false;
}
//日
bool cr (int m,int n){//m月n日
if(m==1||m==3||m==5||m==7||m==8||m==10||m==12) {
if(n>=1&&n<=31)return true;
}
if(m==4||m==6||m==9||m==11){
if(n>=1&&n<=30)return true;
}
if(m==2){
if(ir()){
if(n>=1&&n<=29)return true;
}
else{
if(n>=1&&n<=28)return true;
}
}
return false;
}
int main(){
string s;
cin>>s;
int AA=(s[0]-'0')*10+(s[1]-'0');
int BB=(s[3]-'0')*10+(s[4]-'0');
int CC=(s[6]-'0')*10+(s[7]-'0');

int cnt=0;
// 1.年月日
year=cn(AA);//返回年份
if(cy(BB)){
if(cr(BB,CC)){
a[cnt].n=year;
a[cnt].y=BB;
a[cnt].r=CC;
cnt++;
}
}
//2.月日年
year=cn(CC);//返回年份
if(cy(AA)){
if(cr(AA,BB)){
a[cnt].n=year;
a[cnt].y=AA;
a[cnt].r=BB;
cnt++;
}
}
//3.日月年
year=cn(CC);//返回年份
if(cy(BB)){
if(cr(BB,AA)){
a[cnt].n=year;
a[cnt].y=BB;
a[cnt].r=AA;
cnt++;
}
}
sort(a,a+cnt,com) ;//從小到大

for(int i=0;i<cnt;i++){
//去重
if(i>0){
if(a[i].n==a[i-1].n&&a[i].y==a[i-1].y&&a[i].r==a[i-1].r)continue;
}
cout<<a[i].n<<'-';
if(a[i].y<10)cout<<'0'<<a[i].y<<'-';
else {
cout<<a[i].y<<'-';
}
if(a[i].r<10)cout<<'0'<<a[i].r;
else{
cout<<a[i].r;
}
cout<<endl;

}
return 0;
}

分巧克力

二分例題:

兒童節那天有 K位小朋友到小明家做客。

小明拿出了珍藏的巧克力招待小朋友們。

小明一共有 N塊巧克力,其中第 i 塊是 Hi×Wi的方格組成的長方形。

為了公平起見,小明需要從這 N塊巧克力中切出 K塊巧克力分給小朋友們。

切出的巧克力需要滿足:

  1. 形狀是正方形,邊長是整數
  2. 大小相同

例如一塊 6×5 的巧克力可以切出 6 塊 2×2的巧克力或者 2 塊 3×3 的巧克力。

當然小朋友們都希望得到的巧克力儘可能大,你能幫小明計算出最大的邊長是多少麼?

輸入格式

第一行包含兩個整數 N 和 K。

以下 N行每行包含兩個整數 Hi 和 Wi。

輸入保證每位小朋友至少能獲得一塊 1×1 的巧克力。

輸出格式

輸出切出的正方形巧克力最大可能的邊長。

資料範圍

1N,K105
1Hi,Wi105

輸入樣例:

2 10
6 5
5 6

輸出樣例:

2

題目解析:

首先由每一位小朋友所得巧克力邊長相同-->我們要求的就是滿足條件的一個值(最大邊長)-->對於每一塊巧克力豆花粉乘若干塊這個邊長的小巧克力

所以關鍵就是求一個值

所以很容易想到二分演算法

開始進行二分操作

1.check函式

我們要滿足的是巧克力分出來的個數>=小朋友數

所以需要滿足的條件是for迴圈所有巧克力劃分出來的子塊數求和>=小朋友數

每一塊巧克力在確定劃分邊長是x時能劃分出(h[i]/x)*(w[i]/x)個子塊

2.寫左右邊界

最終答案介於1~105

l=1

r=1e5

3.寫while迴圈

while(l<r){

int mid=l+r+1>>1;//由下面的l,r變化-->確定mid上取整

if(check(mid)){

//劃分塊多了那麼需要增加邊長

l=mid;

}

else{

r=mid-1;

}

}

4.輸出答案l

cout<<l;

完整程式碼
 #include<bits/stdc++.h>
using namespace std;
int n,k;//n塊巧克力,k個小朋友
const int N=1e5+6;
int h[N];//所有巧克力的長
int w[N];//所有巧克力的寬
typedef long long int ll;
bool check(int x){
    ll res=0;
    for(int i=0;i<n;i++){
        res+=(ll)(h[i]/x)*(w[i]/x);
    }
    if(res>=k)return true;
    return false;
}
int main(){
    cin>>n>>k;
    for(int i=0;i<n;i++)cin>>h[i]>>w[i];
    //進行二分(先定l,r然後不斷透過check函式(滿足什麼條件)來找到想要的值)
   //巧克力邊長至少為1
    int l=1;
    //巧克力邊長最多為10的5次方
    int r=1e5;
    while(l<r){
        int mid=l+r+1>>1;
        if(check(mid)){
            l=mid;
        }
        else r=mid-1;
    }
    cout<<l;
    return 0;
}

相關文章