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。

 

题解:“满分做法是在前缀和的基础上,从第2位开始每一位减去前一位,这样我们就得出了m-1位的特征值,把这个特征值哈希成一个数,就满分啦。”——选自大佬Beginner的blog。(并不会哈希,所以这题我没有做。。。)

#include<cstdio>
#include<iostream>
#define MN 100005
using namespace std;
int n,m,ans=1;
struct node{int x,y[31],sum[31];}a[MN];
void work(int u){
    int cnt=1;
    while(a[u].x){
        if(a[u].x&1) a[u].y[cnt]=a[u].sum[cnt]=1;
        a[u].x>>=1; cnt++;
    }
    for(int i=1;i<=m;i++)
        a[u].sum[i]+=a[u-1].sum[i];
}
bool pd(int u,int v){
    for(int i=1;i<m;i++)
        if(a[v].sum[i]-a[u-1].sum[i]!=a[v].sum[i+1]-a[u-1].sum[i+1])
            return false;
    return true;
}
int main()
{
    freopen("cct.in","r",stdin);
    freopen("cct.out","w",stdout);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i].x);
        work(i);
    }
    for(int i=1;i<n;i++)
        for(int j=n;j>i&&j-i+1>ans;j--)
            if(pd(i,j)){
                ans=max(ans,j-i+1); break;
            }
    cout<<ans;
}

 

 

 

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,不过要注意,这题a[0]和a[m+1]也要赋值,以及check中等于x也是可以的。

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int n,m,k,a[50002];
bool check(int x){
    int f=0,ret=0;
    for(int i=1;i<=m+1;i++){
        if(a[i]-f<=x) ret++; 
        else f=a[i];
    }
    if(ret>k) return 0;
    return 1;
}
int main(){
    freopen("mhm.in","r",stdin);
    freopen("mhm.out","w",stdout);
    scanf("%d%d%d",&n,&m,&k);
    for(int i=1;i<=m;i++) scanf("%d",&a[i]);
    a[0]=0;a[m+1]=n;
    sort(a+1,a+1+m);
    int l=0,r=n;
    while(l<=r){
        int mid=(l+r)/2;
        if(check(mid)) l=mid+1;
        else r=mid-1;
    }
    printf("%d",r);
}

 

 

 

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。

 

题解:此题只需要先将点按完成时间排序,然后将时间倒着推,把满足要求的点加入一个优先队列中,答案加上队列最大值即可。

#include<cstdio>
#include<iostream>
#include<queue>
#include<algorithm>
using namespace std;
priority_queue<int> q;
struct node{int t,v;}e[100001];
bool cmp(node a,node b){return a.t>b.t;}
long long ans;
int n;
int main(){
    freopen("aafa.in","r",stdin);
    freopen("aafa.out","w",stdout);
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d%d",&e[i].t,&e[i].v);
    sort(e+1,e+n+1,cmp);int m=1;
    for(int i=e[1].t;i>=1;i--){
        while(i==e[m].t){
            q.push(e[m].v);
            m++;
        }
        if(!q.empty()){ans+=q.top();q.pop();}
    }
    printf("%lld",ans);
}

 

 

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,但是在Beginner大佬(orz)的帮助下,想到了贪心算法,每个点建造费用和遍历过的点向这点连接的费用取个最小值,然后标记这个点,进行O(n^3)的运算,可以过。

#include<cstdio>
#include<iostream>
#define INF 0x7fffffff
using namespace std;
int n,v[305],a[305][305],ans;
bool vis[305];
struct node1{int minn,num;}x,y;
int main(){
    freopen("zzi.in","r",stdin);
    freopen("zzi.out","w",stdout);
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&v[i]);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++) scanf("%d",&a[i][j]);
    for(int i=1;i<=n;i++){
        x.minn=INF;y.minn=INF;
        for(int j=1;j<=n;j++){
            if(!vis[j]&&v[j]<x.minn){x.minn=v[j];x.num=j;}
            if(vis[j])
                for(int k=1;k<=n;k++)
                    if(!vis[k]&&j!=k&&a[j][k]<y.minn){
                        y.minn=a[j][k];
                        y.num=k;
                    }
        }
        if(x.minn<=y.minn){vis[x.num]=true;ans+=x.minn;}
        else{vis[y.num]=true;ans+=y.minn;}
    }
    printf("%d",ans);
}

 

posted @ 2017-09-12 14:06  Vanity  阅读(81)  评论(0)    收藏  举报