21-22-1蓝桥训练9

21-22-1蓝桥训练9

补充本周蓝桥CE两题。

题目
C、试题 算法提高 合并石子
在这里插入图片描述思路:
本题是区间dp的经典例题,当然石子合并问题还有很多的变化,也有一些神奇的优化方法,有兴趣的大佬可以自己去学习一下(这里我给出连接:石子合并问题–动态规划;贪心)

这里我用的是(GarsiaWachs算法)

#include <fstream>
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
using namespace std;
const int N = 50005;
const int INF = 0x3f3f3f3f;

int stone[N];
int n,t,ans;
void combine(int k)
{
    int tmp = stone[k] + stone[k-1];
    ans += tmp;
    t--;
    for(int i=k;i<t;i++)
        stone[i] = stone[i+1];
    int j = 0;
    for(j=k-1;stone[j-1] < tmp;j--)
        stone[j] = stone[j-1];
    stone[j] = tmp;
    while(j >= 2 && stone[j] >= stone[j-2])
    {
        int d = t - j;
        combine(j-1);
        j = t - d;
    }
} 
int main()
{
     scanf("%d",&n);
         for(int i=1;i<=n;i++)
             scanf("%d",&stone[i]);
         stone[0]=INF;
         stone[n+1]=INF-1;
         t = 3;
         ans = 0;
        for(int i=3;i<=n+1;i++)
        {
             stone[t++] = stone[i];
             while(stone[t-3] <= stone[t-1])
                 combine(t-2);
         }
         while(t > 3) combine(t-1);
         printf("%d\n",ans);
         memset(stone,0,sizeof(stone));
     return 0;
}   

E、试题 算法提高 Intersecting Dates
在这里插入图片描述题意:
简单的说,已知nx个时间区间中的每一天,但是要求知道nr个时间区间中的每一天,问需要
新增出几个时间区间,才能到达要求。
如果时间区间只有一天的话,输出该天时间即可,格式:** 月/日/年**(前面四个空格)
否则输出区间开始时间和结束时间。格式** 月/日/年 to 月/日/年**(前面四个空格,第一个月/日/年是开始时间,第二个月/日/年是结束时间)
要是没有新增时间区间,输出** No additional quotes are required.**(前面四个空格)

思路:
直接模拟就行了,我们可以将1700年到2100年中的每一天按顺序转化成数字,然后先记录一下已知区间,随后在读入要求区间的时间将区间对应的每一个数字标记一下,之后再用已知区间将可以消除标记的数字全部删除。最后仍然处于标记状态的数字就是要新增的时间。
同时,我们通过全局变量flag来判断是否有新增区间,没有就输出** No additional quotes are required.**,
两个小细节:
①:每次我们都应该初始化flag和对标记数组vis进行清空。
②:每次询问后要多输出一次换行,不然过不了全部数据。(根据红色框框得出)
在这里插入图片描述

#include<bits/stdc++.h>
using namespace std;
const int N=105;
int t,nx,nr;
int st[N],ed[N];
bool flag;
int days[]={0,31,28,31,30,31,30,31,31,30,31,30,31};
bool vis[150000]; //400*366=146400

bool cek(int x){return (x%4==0&&x%100!=0)||(x%400==0);}

int change(int x){
    int year=x/10000;
    int month=(x%10000)/100;
    int day=x%100;
    int sum=0;
    for(int i=1700;i<year;i++){
        if(cek(i)) sum+=366;
        else sum+=365;
    }
    if(cek(year)) days[2]=29;
    else days[2]=28;
    for(int i=1;i<month;i++) sum+=days[i];
    sum+=day;
    return sum;
}

void get_vis(int start,int end,int type){
    int st1=change(start);
    int ed1=change(end);
    for(int i=st1;i<=ed1;i++) vis[i]=type;
}

void change1(int x,bool kind){
    int year=1700,month=0,day=0,hv=0,te;
    while(1){
        if(cek(year)) te=366;
        else te=365;
        if(hv+te>x) break;
        year++,hv+=te; 
    }

    if(hv==x){
        year--;
        month=12;
        day=31;
    }
    else{
        if(cek(year)) days[2]=29;
        else days[2]=28;
        for(int i=1;i<=12;i++){
            if(hv+days[i]>x) break;
            month++,hv+=days[i];
        }
        if(hv==x) day=days[month];
        else month++,day=x-hv;
        // if(hv==x) day=days[month];
        // else day=x-hv;
    }
    printf("%d/%d/%d",month,day,year);
    if(kind) puts("");
}

void solve(int ci){
    printf("Case %d:\n",ci);
    for(int i=1;i<150000;i++) vis[i]=false;
    for(int i=1;i<=nx;i++) scanf("%d%d",&st[i],&ed[i]);
    for(int i=1;i<=nr;i++){
        int start,end; scanf("%d%d",&start,&end);
        get_vis(start,end,1);
    }
    for(int i=1;i<=nx;i++) get_vis(st[i],ed[i],0);
    for(int i=1;i<150000;i++){
        if(vis[i]){
            flag=true;
            printf("    ");
            if(!vis[i+1]) change1(i,true);
            else{
                change1(i,false);
                printf(" to ");
                for(int j=i+1;j<150000;j++){
                   // cout<<"j="<<j<<"\n";
                    if(vis[j]) continue;
                    else {change1(j-1,true);i=j-1;break;}
                }
            }
        }
    }
    if(!flag) puts("    No additional quotes are required.");
    puts("");
}

int main(){
    while(scanf("%d%d",&nx,&nr)){
        if(nx==0&&nr==0) return 0;
        t++; flag=false;
        solve(t);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值