• 2017/9/10模拟赛


    CCT

    最近学校又发了n本五三题霸,BBS看到后十分高兴。但是,当他把五三拿到手后才发现,他已经刷过这些书了!他又认真地看了一会儿,发现新发的这些五三是2017版的,而他刷的是2016版的。现在他想找出所有他没有刷过的题来刷。每本五三都有m道题,并且它的特征(即它和去年版本的五三的差距)可以用一个m位二进制数来代表,二进制位上的1代表该题不同,0代表该题相同。比如4(100)就代表题目3和去年的有不同、5(101)就代表题目1和题目3和去年的有不同。而BBS热衷于给自己找麻烦,他要选择连续一段的几本五三一起刷,并且要求,所有选择的五三的特征中的所有k位中每一位出现1的次数都相同。他又想去刷最多的书,请你告诉他,他最多能刷多少本书?

    输入格式:

    第一行为两个整数 n、m,接下来的n行为 n 个整数,表示每本五三的特征。

    输出格式:

    一个整数,表示BBS最多能刷几本书。

    样例输入

    样例输出

    7 3

    7

    6

    7

    2

    1

    4

    2

    4

    样例解释:

    这7本五三的特征分别为111,110,111,010,001,100,010。选择第3本至第6本五三,这些五三的特征中每一位都出现了2次1。当然,选择第4本到第6本也是可以的,这些五三的特征中每一位都出现了1次1。只是这样子BBS刷的书的数量就少了,他就会不高兴。

    数据范围:

    对于 100%的数据:1<=n<=100000,1<=k<=30。

    题解:首先我们可以想到,对这个数的每个二进制位做一个前缀和,若第i到第j本书满足条件,则每一位的sum[j]-sum[i]都相等,这样的复杂度是n^2,再加入以下优化:①j从末尾开始搜,若搜到答案,更新后直接break;②若j-i+1小于等于当前ans,之后就不用搜了。这样暴力大概能拿60分。

    代码如下:

     1 #include<cstdio>
     2 #include<iostream>
     3 #define MN 100005
     4 using namespace std;
     5 int n,m,ans=1;
     6 struct node{int x,y[31],sum[31];}a[MN];
     7 void work(int u){
     8     int cnt=1;
     9     while(a[u].x){
    10         if(a[u].x&1) a[u].y[cnt]=a[u].sum[cnt]=1;
    11         a[u].x>>=1; cnt++;
    12     }
    13     for(int i=1;i<=m;i++)
    14         a[u].sum[i]+=a[u-1].sum[i];
    15 }
    16 bool pd(int u,int v){
    17     for(int i=1;i<m;i++)
    18         if(a[v].sum[i]-a[u-1].sum[i]!=a[v].sum[i+1]-a[u-1].sum[i+1])
    19             return false;
    20     return true;
    21 }
    22 int main()
    23 {
    24     freopen("cct.in","r",stdin);
    25     freopen("cct.out","w",stdout);
    26     scanf("%d%d",&n,&m);
    27     for(int i=1;i<=n;i++){
    28         scanf("%d",&a[i].x);
    29         work(i);
    30     }
    31     for(int i=1;i<n;i++)
    32         for(int j=n;j>i&&j-i+1>ans;j--)
    33             if(pd(i,j)){
    34                 ans=max(ans,j-i+1); break;
    35             }
    36     cout<<ans;
    37 }

    题解:满分做法是在前缀和的基础上,从第2位开始每一位减去前一位,这样我们就得出了m-1位的特征值,把这个特征值哈希成一个数,就满分啦。

    -----------------------------------------------------------------华丽的分割线------------------------------------------------------------------------

    MHM

           LGL今天一共要上n节课,这n节课由0标号至n。由于过度劳累,除了第0节课和第n节课,LGL还打算睡上m节课,所以他做了一个睡觉计划表。通过小道消息,LGL得知WQ今天会在学校中检查,所以他想少睡k节课。但是由于某些原因,他又想使相邻的两节睡觉的课之间上的课数量的最小值最大。由于他很困,所以他请你来帮他计算这个值。

     

    输入格式:

    第一行为三个整数 n、m、k,接下来的m行为m个整数ai,表示睡觉计划表中LGL想要睡觉的课。

    输出格式:

    一个整数,表示题目所求的值。

    样例输入

    样例输出

    25 5 2

    14

    11

    17

    2

    21

    3

    样例解释:

    选择第2节和第14节不睡觉,这样子相邻的两节睡觉的课之间上的课数量的最小值为3,即第17节和第21节之间和第21节到第25节之间。没有答案更大的删除方案。

    数据范围:

    对于100%的数据:1<=n<=109,1<=k<=m<=50000,0<ai<n。

    题解:原题跳石头。。。二分答案+check,做完啦。

    代码如下:

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<algorithm>
     4 #define MN 50005
     5 using namespace std;
     6 int n,m,k,a[MN];
     7 bool check(int x){
     8     int fst=0,ret=0;
     9     for(int i=1;i<=m+1;i++){
    10         if(a[i]-fst<x) ret++;
    11         else fst=a[i];
    12         if(ret>k) return false;
    13     }
    14     return true;
    15 }
    16 int main()
    17 {
    18     freopen("mhm.in","r",stdin);
    19     freopen("mhm.out","w",stdout);
    20     scanf("%d%d%d",&n,&m,&k);
    21     for(int i=1;i<=m;i++) scanf("%d",&a[i]);
    22     a[m+1]=n; sort(a,a+2+m);
    23     int l=0,r=n;
    24     while(l<=r){
    25         int mid=(l+r)>>1;
    26         if(check(mid)) l=mid+1;
    27         else r=mid-1;
    28     }
    29     printf("%d",r-1);
    30     return 0;
    31 }

     -----------------------------------------------------------------华丽的分割线------------------------------------------------------------------------

    AAFA

     YYH有n道题要做。每一道题都有一个截止日期t,只要在该日期之前做完,他的父亲LRB就会奖励他w元钱。令人惊讶的是,每一道题他都只需要1秒来做。请问他最多能从父亲那里拿到多少钱?

    输入格式:

    第一行为一个整数 n,接下来的n行每一行都有两个数ti和wi,分别表示第i题的截止日期和奖励。

    输出格式:

    一个整数,表示YYH的最大获利。

    样例输入

    样例输出

    3

    2 10

    1 5

    1 7

    17

    样例解释:

                         第1秒做第3道题,第2秒做第1道题。

    数据范围:

    对于 100%的数据:1<=n、ti 、wi <=100000。

    题解:首先,我们把时间轴反过来,把所有大于等于当前时间的i加入堆,取其中的最大值加入答案并pop,当然,要特判堆中没有元素的情况,否则会re。

    代码如下:

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<algorithm>
     4 #include<queue>
     5 #define MN 100005
     6 using namespace std;
     7 int n,m=1;
     8 long long ans;
     9 struct node{int t,v;}e[MN];
    10 priority_queue<int> pq;
    11 bool cmp(node a,node b){return a.t>b.t;}
    12 int main()
    13 {
    14     freopen("aafa.in","r",stdin);
    15     freopen("aafa.out","w",stdout);
    16     scanf("%d",&n);
    17     for(int i=1;i<=n;i++) scanf("%d%d",&e[i].t,&e[i].v);
    18     sort(e+1,e+1+n,cmp);
    19     for(int i=e[1].t;i>=1;i--){
    20         while(e[m].t==i){pq.push(e[m].v); m++;}
    21         if(pq.empty()) continue;
    22         ans+=pq.top(); pq.pop();
    23     }
    24     printf("%lld",ans);
    25     return 0;
    26 }

     -----------------------------------------------------------------华丽的分割线------------------------------------------------------------------------

    ZZI

           YYH拿到了父亲给的钱欣喜若狂,把这些钱拿来造了n栋房子。现在他要给这些房子通电。他有两种方法:第一种是在房间里搭核电发电机发电,对于不同的房子,他需要花不同的代价Vi;,第二种是将有电的房子i的电通过电线通到没电的房子j中,这样子他需要花的代价为aij。他现在请你帮他算出他最少要花多少钱才能让所有的房子通上电。

    输入格式:

    第一行为一个整数 n。接下来的n行为 n 个整数vi,再接下来的n行每行n个数,第i行第j列的数表示aij

    输出格式:

    一个整数,表示最小代价。

    样例输入

    样例输出

    4
    5

    4

    4

    3
    0 2 2 2
    2 0 3 3
    2 3 0 4
    2 3 4 0

    9

    样例解释:

    在第4栋房子造核电发电机,再将其他三栋房子通过电线连向它。

    数据范围:

    对于 100%的数据:1<=n<=300,1<=vi,aij<=100000,保证aii=0,aij=aji

    题解:这题似乎是裸的MST,把每个点向自己连一条边(好像),但是,我们用贪心算法来做就可以啦。每次,我们枚举所有未vis的点对他们的v取一个min,然后,对所有已vis的点所遍历到未vis点的a取一个min,2个min再取一个min,将该点发电,一共进行n次这样的操作,复杂度大约是n^3。

    代码如下:

     1 #include<cstdio>
     2 #include<iostream>
     3 #define INF 0x7fffffff
     4 using namespace std;
     5 int n,v[305],a[305][305],ans;
     6 bool vis[305];
     7 struct node{int minn,num;}x,y;
     8 int main()
     9 {
    10     freopen("zzi.in","r",stdin);
    11     freopen("zzi.out","w",stdout);
    12     scanf("%d",&n);
    13     for(int i=1;i<=n;i++) scanf("%d",&v[i]);
    14     for(int i=1;i<=n;i++)
    15         for(int j=1;j<=n;j++) scanf("%d",&a[i][j]);
    16     for(int i=1;i<=n;i++){
    17         x.minn=INF; y.minn=INF;
    18         for(int j=1;j<=n;j++){
    19             if(!vis[j]&&v[j]<x.minn){x.minn=v[j];x.num=j;}
    20             if(vis[j])for(int k=1;k<=n;k++)
    21                 if(!vis[k]&&j!=k&&a[j][k]<y.minn){
    22                     y.minn=a[j][k]; y.num=k;
    23                 }
    24         }
    25         if(x.minn<=y.minn){vis[x.num]=true; ans+=x.minn;}
    26         else{vis[y.num]=true; ans+=y.minn;}
    27     }
    28     cout<<ans;
    29 }

    写prim也可以:

    #include<stdio.h>
    #include<string.h>
    #define min(a,b)(a<b?a:b)
    const int maxN=302;
    const int INF=0x7fffffff;
    int n;
    int minW[maxN];
    int w[maxN][maxN];
    bool used[maxN];
    int prim(){
        for(int i=0;i<n;i++)
            minW[i]=INF,used[i]=false;
        minW[0]=0;
        int res=0;
        while(1){
            int v=-1;
            for(int u=0;u<n;u++){
                if(!used[u]&&(v==-1||minW[u]<minW[v]))v=u;
            }
            if(v==-1)break;
            used[v]=true;
            res+=minW[v];
            for(int u=0;u<n;u++)
                if(w[v][u])minW[u]=min(minW[u],w[v][u]);
        }
        return res;
    }
    int main(){
        freopen("zzi.in","r",stdin);
        freopen("zzi.out","w",stdout);
        scanf("%d",&n);
        for(int i=0;i<n;i++)
            scanf("%d",&w[i][n]),w[n][i]=w[i][n];
        w[n][n]=0;
        for(int i=0;i<n;i++)
            for(int j=0;j<n;j++)
                scanf("%d",&w[i][j]);
        n++;
        printf("%d",prim());
    }
  • 相关阅读:
    安徽.NET俱乐部4月份活动图片
    C++ string和数字间的任意转换
    利用C++特性 析构对象(ScopeGuard.h)
    ffmpeg第三方库
    Apifox软件使用技巧
    工作流撤回(activity5)
    pom文件详解
    Java内部类详解成员内部类,局部内部类,匿名内部类,静态内部类
    Docker 详解
    JDK8 新特性 Lambda表达式
  • 原文地址:https://www.cnblogs.com/Beginner-/p/7505864.html
Copyright © 2020-2023  润新知