ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

题解——[六省联考2017]期末考试(模拟+递推)

2019-09-17 19:57:48  阅读:220  来源: 互联网

标签:cha 时刻 六省 题解 课程 成绩 ans now 联考


题解——[六省联考2017]期末考试(模拟+递推)

要写数据分治,但这道题真的水


题面

Description

有n 位同学,每位同学都参加了全部的m 门课程的期末考试,都在焦急的等待成
绩的公布。

第i 位同学希望在第ti 天或之前得知所. 有. 课程的成绩。如果在第ti 天,有至少一
门课程的成绩没有公布,他就会等待最后公布成绩的课程公布成绩,每等待一天就会产
生C 不愉快度。

对于第i 门课程,按照原本的计划,会在第bi 天公布成绩。

有如下两种操作可以调整公布成绩的时间:

  1. 将负责课程X 的部分老师调整到课程Y,调整之后公布课程X 成绩的时间推迟
    一天,公布课程Y 成绩的时间提前一天;每次操作产生A 不愉快度。

  2. 增加一部分老师负责学科Z,这将导致学科Z 的出成绩时间提前一天;每次操
    作产生B 不愉快度。

上面两种操作中的参数X; Y; Z 均可任意指定,每种操作均可以执行多次,每次执
行时都可以重新指定参数。

现在希望你通过合理的操作,使得最后总的不愉快度之和最小,输出最小的不愉快
度之和即可。

Input

从文件exam.in 中读入数据。
第一行三个非负整数A; B;C ,描述三种不愉快度,详见【问题描述】;
第二行两个正整数 n m ,分别表示学生的数量和课程的数量;
第三行n 个正整数ti ,表示每个学生希望的公布成绩的时间;
第四行m 个正整数bi ,表示按照原本的计划,每门课程公布成绩的时间。

Output

输出到文件exam.out 中。
输出一行一个整数,表示最小的不愉快度之和。

in.1
100 100 2
4 5
5 1 2 3
1 1 2 3 3

out.1
6

数据范围与约定

思路

一些性质

1.由题意得,其实影响最后答案的科目一定是排在最后面的科目。

2.如果我们将最后同一时刻上的科目往前移动,而没有移动在这一时刻上的所有科目,那么这之前的移动是无效的。

3.当不考虑特殊条件时,如果 A < B 那么优先选 A 操作,再选 B。否则全部选 B 操作即可。

思考

如果我们枚举时刻 i ,考虑将所有在时刻 i 之后的课程提到 i 时刻来,那么对于时刻 i 而言,这一定是当前时刻的最优解。

发现数据很大,所以我们要预处理出将所有在时刻 i 之后的科目提到 i 时刻后,学生的不满意度 和 提前操作的不满意度 。

由于 A 操作的次数在每个时刻 i 是有限的(不能把科目延迟到 i 之后),我们也要预处理出来。

主要分为两部分:

1.预处理出我们需要的数组。

2.O(n)枚举时间,取最小答案即可(包括一些特判)

处理:

1.我们用2个桶 t[ ] 和 d[ ] 分别记录在 i 时刻学生的时间上限为i的数量结束科目的数量
顺便记录一下最后一科的时间,作为枚举边界。

for( int i = 1 ; i <= N ; ++i )m1 = (int)read() , t[ m1 ]++ ;
for( int i = 1 ; i <= M ; ++i )m1 = (int)read() , las = max( (ll)m1 , las ) , d[ m1 ]++ ;

然后我们枚举时刻 i ,直接预处理出上述三个需要的数组。记录方法为先累加贡献值,再累加个数,自己想想其实很简单的。复杂度 O(n)。

ll tot = 0 , val = 0 ;//∑C 
if( flag != 3 )
    for( int i = 1 ; i <= las ; ++i )
        val += tot*C , tot += t[ i ] , c[ i ] = val ;
tot = 0 , val = 0 ;
for( int i = 1 ; i <= las ; ++i )//A的上限 
    val += tot , tot += d[ i ] , used[ i ] = val ;
tot = 0 , val = 0 ;
for( int i = las ; i >= 1 ; --i )//需要提前的次数
    val += tot , tot += d[ i ] , cha[ i ] = val ;

2.预处理完成之后,我们枚举时间,求出学生的不满意度和提前操作的不满意度之和即可。

特殊点处理:

1 2 点不能使用 A,B ,直接输出 c[ las ]
3 4 点不能使用 B , 全部使用 A , A不够直接 break
13 14 点不能预处理 C , 也不能使用 C , 直接求出提前到最早时间要求处的答案即可。

时间复杂度

综上所述,预处理和递推模拟都是严格 O(n),而且数据分治,复杂度已经优化,在数据更新后20个点只跑了134ms,比大部分数据更新前的人都跑的快。

#include<bits/stdc++.h>
using namespace std ;
#define ll long long
const int MAXN = 100005 ;
inline ll read(){
    ll s=0 ; char g=getchar() ; while(g>'9'||g<'0')g=getchar() ;
    while(g>='0'&&g<='9')s=s*10+g-'0',g=getchar() ; return s ;
}
ll t[ MAXN ] , d[ MAXN ] , used[ MAXN ] , cha[ MAXN ] , c[ MAXN ] ;
ll A , B , C , N , M , ans , las ;//las记录最后一科出来的时间 
int  flag = 0 , flag2 = 0 ;
int check(){
    if( A < B )flag2 = 1 ;
    if( A == 1e9 && B == 1e9 )return 1 ;
    if( A != 1e9 && B == 1e9 )return 2 ;
    if( C == 1e16 )return 3 ;
    return 0 ;
} 
void  prepare(){
    ll tot = 0 , val = 0 ;//∑C 
    if( flag != 3 )
        for( int i = 1 ; i <= las ; ++i )
            val += tot*C , tot += t[ i ] , c[ i ] = val ;
    tot = 0 , val = 0 ;
    for( int i = 1 ; i <= las ; ++i )//A的上限 
        val += tot , tot += d[ i ] , used[ i ] = val ;
    tot = 0 , val = 0 ;
    for( int i = las ; i >= 1 ; --i )
        val += tot , tot += d[ i ] , cha[ i ] = val ;
}
void work(){
    ll now ; ans = c[ las ] ;
    for( int i = las ; i >= 1 ; --i ){
        now = c[ i ] ;
        if( flag2 ){//优先用A 
            if( used[ i ] >= cha[ i ] )now += cha[ i ]*A ;
            else now += used[ i ]*A + ( cha[ i ] - used[ i ] )*B ;
        }
        else
            now += cha[ i ]*B ;
        ans = min( ans , now ) ;
    }
    cout<<ans ;
}
void work2(){//仅使用 A C
    ll now ; ans = c[ las ] ;
    for( int i = las ; i >= 1 ; --i ){
        now = c[ i ] ;
        if( used[ i ] >= cha[ i ] )now += cha[ i ]*A ;
        else break ;
        ans = min( ans , now ) ;
    }
    cout<<ans ;
}
void work3(){//仅使用 A B 
    ans = 0LL ; //上限1e10
    ll fir = 0LL ; 
    for( int i = 1 ; i <= las ; ++i )if( t[ i ] ){ fir = i ; break ; }
    if( flag2 ){//优先用A 
            if( used[ fir ] >= cha[ fir ] )ans += cha[ fir ]*A ;
            else ans += used[ fir ]*A + ( cha[ fir ] - used[ fir ] )*B ;
        }
    else
        ans += cha[ fir ]*B ;
    cout<<ans ;
}
int main(){
    freopen("exam.in","r",stdin);
    freopen("exam.out","w",stdout);
    A = read() , B = read() , C = read() , N = read() , M = read() ;
    int m1 , m2 ;
    for( int i = 1 ; i <= N ; ++i )m1 = (int)read() , t[ m1 ]++ ;
    for( int i = 1 ; i <= M ; ++i )m1 = (int)read() , las = max( (ll)m1 , las ) , d[ m1 ]++ ;
    flag = check() ;
    prepare() ;
    if( flag == 1 ){cout<<c[ las ] ; return 0 ; }
    if( flag == 2 ){ work2() ; return 0 ; }
    if( flag == 3 ){ work3() ; return 0 ; }
    work() ; 
    return 0 ;
}

如有不足,请大佬指出

标签:cha,时刻,六省,题解,课程,成绩,ans,now,联考
来源: https://www.cnblogs.com/ssw02/p/11536513.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有