11.03 P73 模拟+堆+贪心

12 篇文章 0 订阅
11 篇文章 0 订阅

每个测试点时限 1 秒 1 秒 1 秒
内存限制 512MB 512MB 512MB

第二题

【问题描述】

【其实它是第一题啊。。。。】
给你两个日期,问这两个日期差了多少毫秒。
【输入格式】
两行,每行一个日期,日期格式保证为“YYYY-MM-DD hh:mm:ss”这种形式。第二个日期时间一定比第一个日期时间要大两个日期的年份一定都是 21 世纪的年份。
【输出格式】
一行一个整数代表毫秒数。
【样例输入 1】
2000-01-01 00:00:00
2000-01-01 00:00:01
【样例输出 1】
1000
【样例输入 2】
2000-01-01 00:00:00
2000-11-11 00:00:00
【样例输出 2】
27216000000
【样例解释】
从前有座山。
【数据范围与规定】
对于10%的数据, 两个日期相同。
对于20%的数据,两个日期只有秒数可能不同。
对于30%的数据,两个日期只有秒数、分钟数可能不同。
对于40%的数据,两个日期的年月日一定相同。
对于60%的数据,两个日期的年月一定相同。
对于80%的数据,两个日期的年份一定相同。
对于100%的数据,两个日期一定都是 21 世纪的某一天,且第二个日期一定大于等于第一个日期。

题解

分别算出第一个日期和第二个日期与2000-01-01 00:00:00 的时间差,然后把两个时间差相减
这样就可以避免冗杂的判断和计算

代码
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const long long Y=31536000000ll;//一年多少毫秒
const long long D=86400000ll;//一天
const long long H=3600000ll;///一小时
const long long F=60000ll;//一分钟
const long long E=1000ll;//一秒

string s1,s2,s3,s4;

long long y1,m1,d1,h1,f1,e1;
long long y2,m2,d2,h2,f2,e2;
//      年 月 日   时 分 秒
long long ans1,ans2;

int tmp[50]={0,2000,2004,2008,2012,2016,2020,2024,2028,2032,2036,2040,
2044,2048,2052,2056,2060,2064,2068,2072,2076,2080,2084,2088,
2092,2096,2100};//闰年表,便于快速的查询从2000--当前年份的闰年数
int cnt[]={0,31,28,31,30,31,30,31,31,30,31,30,31};//每月有多少天,,打表滋滋
void read(){
    cin>>s1>>s3;
    cin>>s2>>s4;
    for(int i=0;i<=3;i++) y1=y1*10+s1[i]-'0';
    for(int i=0;i<=3;i++) y2=y2*10+s2[i]-'0';
    m1=(s1[5]-'0')*10+s1[6]-'0';
    m2=(s2[5]-'0')*10+s2[6]-'0';
    d1=(s1[8]-'0')*10+s1[9]-'0';
    d2=(s2[8]-'0')*10+s2[9]-'0';
    h1=(s3[0]-'0')*10+s3[1]-'0';
    h2=(s4[0]-'0')*10+s4[1]-'0';
    f1=(s3[3]-'0')*10+s3[4]-'0';
    f2=(s4[3]-'0')*10+s4[4]-'0';
    e1=(s3[6]-'0')*10+s3[7]-'0';
    e2=(s4[6]-'0')*10+s4[7]-'0';
}
void work1(){
    ans1=(y1-2000)*Y;
    int x=lower_bound(tmp+1,tmp+50+1,y1)-tmp-1;//查有多少个闰年,当前年份不包括在内
    ans1+=x*D;
    for(int i=1;i<m1;i++){
        ans1+=cnt[i]*D;//处理月,当前月不包括在内
    }
    if(tmp[x+1]==y1&&m1>2) ans1+=D;//如果当前年是闰年,且大于二月,多加29号那一天
    ans1+=(d1-1)*D;//处理天
    ans1+=(h1)*H;
    ans1+=(f1)*F;
    ans1+=(e1)*E;
}
void work2(){
    ans2=(y2-2000)*Y;
    int x=lower_bound(tmp+1,tmp+50+1,y2)-tmp-1;
    ans2+=x*D;
    for(int i=1;i<m2;i++){
        ans2+=cnt[i]*D;
    }
    if(tmp[x+1]==y2&&m2>2) ans2+=D;
    ans2+=(d2-1)*D;
    ans2+=(h2)*H;
    ans2+=(f2)*F;
    ans2+=(e2)*E;
}
int main(){
    freopen("two.in","r",stdin);
    freopen("two.out","w",stdout);
    read();//读入处理
    /*printf("%d %d %d %d %d %d\n",y1,m1,d1,h1,f1,e1);
    printf("%d %d %d %d %d %d\n",y2,m2,d2,h2,f2,e2);*/
    work1();
    work2();
    printf("%lld",ans2-ans1);
    return 0;
}

死亡

【问题描述】

现在有m位置可以打 sif,有n+ 1个人在排队等着打 sif。 现在告诉你前n个人每个人需要多长的时间打 sif,问你第n+ 1个人什么时候才能打 sif。(前n个人必须按照顺序来)
【输入格式】
第一行两个整数n,m如上所述。
接下来n行每行一个整数代表每个人所需要用的时间。
【输出格式】
一行一个整数表示答案。
【样例输入】
3 2
1 1 1
【样例输出】
1
【样例解释】
山里有座庙。
【数据规模与约定】
对于100%的数据,每个人所需用的时间不超过105。
测试点 n,m 测试点 n m
1 10 10 1 5000 500
2 20 10 2 100000 5000
3 50 10 3 100000 10000
4 1000 500 4 100000 20000
5 2000 500 5 100000 50000

题解

用一个小根堆维护m个位置的当前时间节点,因为必须按照顺序打,所以每次取出最小的位置,将当前等待的人安排在此位置上,再push进去

代码
#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
const int N=100000+500;
priority_queue<long long,vector<long long>,greater<long long> >Q;
int n,m,cnt;
long long now,a[N];
int main(){
    freopen("death.in","r",stdin);
    freopen("death.out","w",stdout);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%lld",&a[i]);
    }
    for(int i=1;i<=m;i++) Q.push(a[i]);
    cnt=m+1;
    while(!Q.empty()){
        now=Q.top();
        Q.pop();
        if(cnt==n+1) {
            printf("%lld",now);
            return 0;
        }
        Q.push(now+(a[cnt++]));
    }
    return 0;
}

凝视

【问题描述】

背包是个好东西,希望我也有。
给你一个二维的背包,它的体积是n×m,现在你有一些大小为1 × 2和1×3的物品,每个物品有自己的价值。你希望往背包里面装一些物品,使得它们的价值和最大,问最大的价值和是多少。
【输入格式】
第一行一个整数 t代表该测试点的数据组数。
对于每组数据,第一行有四个整数n,m,n1,n2,其中n1,n2分别代表大小为1 × 2和大小为1 × 3的物品个数。
接下来一行有n1个数代表每个1 × 2物品的价值。
接下来一行有n2个数代表每个1 × 3物品的价值。
【输出格式】
对于每组询问,输出能够达到的价值最大值。
【样例输入】
1
2 3 2 2
1 2
1 2
【样例输出】
4
【样例解释】
庙里有座山。
【数据规模与约定】
对于20%的数据, n,m ≤ 10, n1, n2 ≤ 100。
对于70%的数据, n,m ≤ 100,n1, n2≤ 2000。
对于100%的数据, 1 ≤ t ≤ 10,1 ≤n,m ≤ 500,0 ≤ n1, n2 ≤ 10000。

错的不严格题解

一个看起来很像DP的贪心
相同规格的物品,肯定优先选择大的,先sort,维护一个前缀和
价值都是正数,能塞就塞

1X3的方块很容易被卡,考虑先放1X3的方块,在每一行中尽可能的多放,剩下的空隙能塞就塞
交换行列的数值(相当于旋转一下),取max,就能得出1X3的方块能放的范围
maxx=max(n*(m/3)+(m%3)*(n/3),m*(n/3)+(n%3)*(m/3));

贪心:
枚举放多少个3,(整个背包体积-3的体积)/2就是2能放得数量
要保证正确性,就必须满足铺了3之后,剩下的面积能够完全被2铺满,或者仅剩1单位面积

证明:
显然,对于矩形,1X2的方块要么将其全部铺满,要么仅剩1单位面积

如下图

将3按次序铺好
剩下的区域是① ② ③

分别考虑每个区域能否被铺满

   ①  ②  ③
1  √  √  √
2  ×  √  √
3  √  ×  √
4  √  √  ×

5  √  ×  ×
6  ×  √  ×
7  ×  ×  √

8  ×  ×  ×

1-4种情况,显然被铺满或者仅剩一个方块
5 ② ③分别剩余1 将②中的空格置于最右边,③中的空格置于右上方,这两个空格能被同一块方块铺满,整个图形被铺满
6 ① ③分别剩余1 ①的宽肯定是1,将①中的方块置于最下方,③中的空格置于右下方,这两个空格能被同一块方块铺满,整个图形被铺满
7 ① ②分别剩余1,②的左侧取出一块3,和①中的一块2+空格交换,这样①被铺满,②的宽度由奇数变成了偶数,也被铺满,整个图形被铺满
8 舍弃任一区域,按照5-7的操作处理,整个图形只剩余1个方块

考试的时候,/打成%,ij打反 从100变成0 我也是很棒棒。。。。

bug

5*5的矩阵,能放下8个3,但是按照上述解释,乖巧的摆放3的话,只能放下7个
以上前提不成立,任意证明均不成立了。。

代码
错的cpp,但是我能A啊,面对数据编程qwq
#include<iostream>
#include<cstdio>
#include<algorithm>
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b)) 
using namespace std;
const int N=10000+500;
int a[N],b[N],s1[N],s2[N];
int n,m,n1,n2,t;
int maxx,ans;
bool cmp(int a,int b){
    return a>b;
}
void init(){
    for(int i=0;i<N;i++){
        a[i]=0,b[i]=0;
        s1[i]=0,s2[i]=0;
    }
    maxx=-1;
    ans=-1;
}
int main(){
    freopen("eyesight.in","r",stdin);
    freopen("eyesight.out","w",stdout);
    scanf("%d",&t);
    while(t--){
        scanf("%d%d%d%d",&n,&m,&n1,&n2);
        init();

        for(int i=1;i<=n1;i++) scanf("%d",&a[i]);//1*2 
        for(int i=1;i<=n2;i++) scanf("%d",&b[i]);//1*3
        sort(a+1,a+n1+1,cmp);
        sort(b+1,b+n2+1,cmp);
        for(int i=1;i<=n1;i++) s1[i]=s1[i-1]+a[i];
        for(int i=1;i<=n2;i++) s2[i]=s2[i-1]+b[i];

        maxx=max(n*(m/3)+(m%3)*(n/3),m*(n/3)+(n%3)*(m/3));
        maxx=min(maxx,n2);

        for(int i=0;i<=maxx;i++){
            int ret=n*m-i*3;
            int j=min(n1,ret/2);//!!!
            ans=max(ans,s1[j]+s2[i]);//!!!
        }
        printf("%d\n",ans);
    }
    return 0;
} 
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>

using namespace std;

const int maxn=10010;

int n,m,n1,n2,y[maxn],z[maxn],sum[maxn];

bool cmp(int a,int b)
{
    return a>b;
}

int main()
{
    freopen("eyesight.in","r",stdin);
    freopen("eyesight.out","w",stdout);

    int t;
    scanf("%d",&t);
    for (;t--;)
    {
        scanf("%d%d%d%d",&n,&m,&n1,&n2);
        for (int a=1;a<=n1;a++)
            scanf("%d",&y[a]);
        for (int a=1;a<=n2;a++)
            scanf("%d",&z[a]);
        sort(y+1,y+n1+1,cmp);
        sort(z+1,z+n2+1,cmp);
        for (int a=1;a<=n1;a++)
            y[a]+=y[a-1];
        for (int a=1;a<=n2;a++)
            z[a]+=z[a-1];
        int delta;
        if (n%3==2 && m%3==2 && (n==2 || m==2)) delta=4;
        else delta=n*m%3;
        int ans=0,limit=min(n2,(n*m-delta)/3);
        for (int a=0;a<=limit;a++)
            ans=max(ans,z[a]+y[min(n1,(n*m-a*3)>>1)]);
        printf("%d\n",ans);
    }

    return 0;
}

tips:

result :100+100+0
qwqT3不翻车,比std跑的快呢。。。
脑子是个好东西,希望我有。。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值