20170910模拟赛

发现,标题还挺押韵的。

似乎。每一题都能找到原题。。

切题如切菜,水题模拟赛 

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。 

这题就十分有趣了,用hash做,而且原题是——黄金阵容均衡(洛谷_1360)

具体看我上一个博客。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
inline int read(){
    int num=0,t=1;char c=getchar();
    while(c>'9'||c<'0'){if(c=='-')t=-1;c=getchar();}
    while(c<='9'&&c>='0'){num=(num<<1)+(num<<3)+c-'0';c=getchar();}
    return num*t;
}
const int mod=1000007,N=100010;
int a[N][33],ans=0,m,n,cnt=0;
int hash[mod],g[N][33],nxt[N],fir[N];
void ins(int x,int y){
    for(int i=hash[x];;i=nxt[i])
        if(!i){ 
            nxt[++cnt]=hash[x];hash[x]=cnt;fir[cnt]=y;
            for(int j=1;j<=m;j++)g[cnt][j]=a[y][j];
            break;
        }
        else{
            int j;
            for(j=1;j<=m;j++)if(g[i][j]!=a[y][j])break;
            if(j>m)break;
        }
}
int find(int x,int y){
    for(int i=hash[x];i;i=nxt[i]){
        int j;
        for(j=1;j<=m;j++)if(g[i][j]!=a[y][j])break;
        if(j>m)return y-fir[i];
    }
    return 0;
}
int main()
{
    freopen("cct.in","r",stdin);
    freopen("cct.out","w",stdout);
    n=read();m=read();
    for(int i=1;i<=n;i++){
        int x=read();
        for(int j=1;j<=m;j++)
            a[i][j]=a[i-1][j]+((x>>(j-1))&1);
        for(int j=m;j>=1;j--)
            a[i][j]-=a[i][1];
    }
    ins(0,0);
    for(int i=1;i<=n;i++){
        int tot=0;
        for(int j=1;j<=m;j++)tot=(tot+(a[i][j]%mod+mod)*j)%mod;
        ins(tot,i);ans=max(ans,find(tot,i));
    }
    printf("%d",ans);
    return 0;
}
View Code

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。 

这题也很明显了吧,贪心加二分,某年的day2t1——在我以前的博客中也能发现。

 就是要修改一点点,可惜,我连改都没改,就交上去了,结果,wa得很严重。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
inline int read(){
    int num=0,t=1;char c=getchar();
    while(c>'9'||c<'0'){if(c=='-')t=-1;c=getchar();}
    while(c<='9'&&c>='0'){num=(num<<1)+(num<<3)+c-'0';c=getchar();}
    return num*t;
}
int L,n,m,a[50010];
int check(int num){
    int la=0,cnt=0;
    for(int i=1;i<=n;i++)
        if(a[i]-la<=num)cnt++;
        else la=a[i];
    return cnt;
}
int ef(){
    int l=1,r=L,mid,ans;
    while(l<=r){
        mid=(l+r)>>1;
        if(check(mid)<=m){ans=mid;l=mid+1;}
        else r=mid-1;
    }
    return ans;
}
int main()
{
    freopen("mhm.in","r",stdin);
    freopen("mhm.out","w",stdout);
    L=read();n=read();m=read();
    for(int i=1;i<=n;i++)a[i]=read();
    sort(a+1,a+1+n);a[++n]=L;
    printf("%d\n",ef());
    return 0;
}
View Code

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。

这题!!也是有原题的,是本人暑假集训时,最后一天中测试的一题。

详情见http://www.cnblogs.com/Yzyet/p/7157806.html

其实,就算不知道有原题,也是很简单的,用一个小根堆,随便乱搞一下,就过了。

有一点需要注意的是,需要开longlong。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
inline int read(){
    int num=0,t=1;char c=getchar();
    while(c>'9'||c<'0'){if(c=='-')t=-1;c=getchar();}
    while(c<='9'&&c>='0'){num=(num<<1)+(num<<3)+c-'0';c=getchar();}
    return num*t;
}
long long sum=0;
int a[100010],cnt=0,n;
struct note{int t,w;}b[100010];
bool cmp(note a,note b){return a.t<b.t;}
void add(int num){
    a[++cnt]=num;int x=cnt,y;
    while(x>1){
        y=x>>1;
        if(a[y]<=a[x])break;
        swap(a[x],a[y]);x=y;
    }
}
int get(){
    int ans=a[1],x=1,y;a[1]=a[cnt--];
    while(x<=(cnt>>1)){
        y=x<<1;
        if(y<cnt&&a[y+1]<a[y])y++;
        if(a[y]>=a[x])return ans;
        swap(a[x],a[y]);x=y;
    }
    return ans;
}
int main()
{
    freopen("aafa.in","r",stdin);
    freopen("aafa.out","w",stdout);
    n=read();
    for(int i=1;i<=n;i++){
        int t=read(),w=read();
        b[i].t=t;b[i].w=w;sum+=w;
    }
    sort(b+1,b+1+n,cmp);int num=0;
    for(int i=1;i<=n;i++){
        if(b[i].t!=b[i-1].t)
            while(num>b[i-1].t)num--,sum-=get();
        add(b[i].w);num++;
    }
    while(num>b[n].t)num--,sum-=get();
    printf("%I64d\n",sum);
    return 0;
}
View Code

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

这是最后一题了,真是可惜,出题人瞒不住我们,每题都被找到原题。

似乎和洛谷——买礼物很想,详情见http://www.cnblogs.com/Yzyet/p/7257551.html

再说啦,这题就是裸的最小生成树,建个虚点,一切就很简单了。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
inline int read(){
    int num=0,t=1;char c=getchar();
    while(c>'9'||c<'0'){if(c=='-')t=-1;c=getchar();}
    while(c<='9'&&c>='0'){num=(num<<1)+(num<<3)+c-'0';c=getchar();}
    return num*t;
}
const int N=310,M=100010;
struct edge{int f,t,c;}e[M];
bool cmp(edge a,edge b){return a.c<b.c;}
int fa[N],n,m=0,ans=0;
void init(){for(int i=0;i<=n;i++)fa[i]=i;}
int find(int x){
    return fa[x]==x?x:fa[x]=find(fa[x]);
}
void unite(int x,int y){
    x=find(x);y=find(y);
    if(x!=y)fa[x]=y;
}
void kru(){
    init();sort(e+1,e+m+1,cmp);
    for(int i=1;i<=m;i++){
        if(find(e[i].f)==find(e[i].t))continue;
        unite(e[i].f,e[i].t);ans+=e[i].c;
    }
}
int main()
{
    freopen("zzi.in","r",stdin);
    freopen("zzi.out","w",stdout);
    n=read();int x;
    for(int i=1;i<=n;i++){
        x=read();
        e[++m]=(edge){0,i,x};
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            x=read();if(i==j)continue;
            e[++m]=(edge){i,j,x};
        }
    }
    kru();printf("%d\n",ans);
    return 0;
}
View Code

本文由Yzyet编写,网址为www.cnblogs.com/Yzyet。非Yzyet同意,禁止转载,侵权者必究。

转载于:https://www.cnblogs.com/Yzyet/p/7523132.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值