Educational Codeforces Round 28 题解

来源:互联网 发布:软件测试简单吗 编辑:程序博客网 时间:2024/06/06 09:39

比赛链接:http://codeforces.com/contest/846

A. Curriculum Vitae

题意:

解法:水题,直接模拟即可。

#include <bits/stdc++.h>using namespace std;const int maxn = 105;int n, a[maxn];int main(){    scanf("%d", &n);    for(int i=1; i<=n; i++) scanf("%d", &a[i]);    int ans=0;    for(int i=0; i<=n; i++){        int cur = 0;        for(int j=1;j<=i;j++) cur+=a[j]==0;        for(int j=i+1;j<=n;j++) cur+=a[j]==1;        ans = max(ans, cur);    }    printf("%d\n", ans);    return 0;}

B. Math Show

题意:n个任务,每个任务包含k个子任务,每个子任务要花t[i]的时间,每完成一个子任务可以赚1块钱,如果完整的完成一个任务可以再追加赚1块钱,现在有M的时间,问在这个时间限制里面能赚的最多的钱。

解法:枚举完整完成的任务的个数,然后把时间排序,贪心算答案,取最大值。

#include <bits/stdc++.h>using namespace std;int t[50];int main(){    int n, k, m, sum = 0;    scanf("%d%d%d",&n,&k,&m);    for(int i=1; i<=k; i++) scanf("%d", &t[i]), sum += t[i];    sort(t+1, t+k+1);    int ans = 0;    for(int i=0; i<=n; i++){        if(m<sum*i) continue;        int ff = m-sum*i;        int now = (k+1)*i;        for(int j=1; j<=k; j++){            int xishu = min(n-i, ff/t[j]);            now += xishu;            ff -= xishu*t[j];        }        ans = max(ans, now);    }    return 0*printf("%d\n", ans);}

C. Four Segments

题意:给了一个n个数的序列(n<=5000),现在求一组(i,j,k)使得sum(0,i)-sum(i,j)+sum(j,k)-sum(k,n)最大,如果有多个最大值任意输出。

解法:直接O(n^3)枚举显然T,考虑优化。枚举一个j找到前面的最大值和后面的最大值就可以了,变成O(n^2),开始是写的set找最大值,结果T了。就直接O(n)扫一遍。


#include <bits/stdc++.h>using namespace std;typedef long long LL;const int maxn = 5010;int n, a[maxn];LL sum[maxn];set <pair<LL,int>> s1, s2;LL solve(int l, int r){    if(l==r) return 0;    else if(l==0) return sum[r-1];    else return sum[r-1]-sum[l-1];}int main(){    scanf("%d",&n);    for(int i=0;i<n;i++) scanf("%d",&a[i]);    sum[0]=a[0];    for(int i=1;i<n;i++) sum[i]=sum[i-1]+a[i];    LL ans = -1e18;    int pos1, pos2, pos3;    for(int mid=0;mid<=n;mid++){        //s1.clear();        //s2.clear();        //for(int i=0;i<=mid;i++) s1.insert(make_pair(solve(0,i)-solve(i,mid), i));        //for(int i=mid;i<=n;i++) s2.insert(make_pair(solve(mid,i)-solve(i,n), i));        LL now1=-1e18, now2=-1e18;        int t1, t2;        for(int i=0;i<=mid;i++){            if(solve(0,i)-solve(i,mid)>now1){                now1=solve(0,i)-solve(i,mid);                t1=i;            }        }        for(int i=mid;i<=n;i++){            if(solve(mid,i)-solve(i,n)>now2){                now2=solve(mid,i)-solve(i,n);                t2=i;            }        }        if(ans < now1 + now2){            ans = now1 + now2;            pos1 = t1;            pos3 = t2;            pos2 = mid;        }//        ans = max(ans, (*s1.rbegin()).first+(*s2.rbegin()).first);//        if(ans==(*s1.rbegin()).first+(*s2.rbegin()).first){//            pos1 = (*s1.rbegin()).second;//            pos3 = (*s2.rbegin()).second;//            pos2 = mid;//        }    }    return 0*printf("%d %d %d\n", pos1, pos2, pos3);}

D. Monitor

题意:一份n*m的显示屏上某些像素点(xi,yi)在t[i]时间会坏掉,如果坏的像素点连成k*k大小,这个显示屏就不能用了,问显示屏损坏的最小的时间,如果不会损坏,输出-1

解法:直接2分时间,那么这个问题就变成了能否找到k*k的矩阵,直接二维前缀和O(n^2)即可。

#include <bits/stdc++.h>using namespace std;const int maxn = 505;int n,m,k,q,a[maxn][maxn],b[maxn][maxn],sum[maxn][maxn];struct node{    int x,y,t;}Q[maxn*maxn];bool check(int x){    memset(b, 0, sizeof(b));    for(int i=1; i<=n; i++){        for(int j=1; j<=m; j++){            if(a[i][j]>=0) b[i][j] = (a[i][j]<=x);        }    }    for(int i=1; i<=n; i++)        for(int j=1; j<=m; j++)            b[i][j] += b[i-1][j];    for(int i=1; i<=n; i++)         for(int j=1; j<=m; j++)            b[i][j] += b[i][j-1];    for(int i=k; i<=n; i++){        for(int j=k; j<=m; j++){            if(b[i][j]-b[i-k][j]-b[i][j-k]+b[i-k][j-k]==k*k) return 1;        }    }    return 0;}int main(){    scanf("%d%d%d%d", &n,&m,&k,&q);    int l = 0, r = 0, ans;    memset(a, -1, sizeof(a));    for(int i=1; i<=q; i++){        scanf("%d%d%d", &Q[i].x,&Q[i].y,&Q[i].t);        a[Q[i].x][Q[i].y] = Q[i].t;        r = max(r, Q[i].t);    }    if(check(r+1) == false){        return 0*puts("-1");    }    while(l<=r){        int mid = (l+r)/2;        if(check(mid)) ans=mid,r=mid-1;        else l=mid+1;    }    printf("%d\n", ans);    return 0;}

E. Chemistry in Berland


#include <bits/stdc++.h>using namespace std;typedef long long LL;const LL inf = 110000000000000000;const int maxn = 100010;struct edge{    int to,next;    LL dis;    edge(){}    edge(int _to, int _next, LL _dis){        to = _to;        next = _next;        dis = _dis;    }}E[maxn];int n, edgecnt, head[maxn];LL a[maxn], b[maxn];void init(){    edgecnt = 0;    memset(head, -1, sizeof(head));}void add(int u, int v, LL w){    E[edgecnt].to = v, E[edgecnt].dis = w, E[edgecnt].next = head[u], head[u] = edgecnt++;}void dfs(int x, int fa, LL val){    for(int i=head[x]; ~i; i=E[i].next){        dfs(E[i].to, x, E[i].dis);    }    if(a[x]<b[x]) b[fa] += b[x]-a[x];    else if(a[x]>b[x]){        double tmp = (double)(b[x]-a[x])*val;        if(tmp<-inf){            printf("NO");            exit(0);        }        b[fa]-=(a[x]-b[x])*val;        if(b[fa]<-inf){            printf("NO");            exit(0);        }    }}int main(){    scanf("%d", &n);    init();    for(int i=1; i<=n; i++) scanf("%lld", &b[i]);    for(int i=1; i<=n; i++) scanf("%lld", &a[i]);    for(int i=2; i<=n; i++){        int x;        LL k;        scanf("%d%lld",&x,&k);        add(x, i, k);    }    for(int i=head[1];~i;i=E[i].next){        dfs(E[i].to, 1, E[i].dis);    }    if(b[1] < a[1]) return 0*puts("NO");    else return 0*puts("YES");}
F. Random Query

题意:一个数列,随机选l,r,f(l,r)为l,r区间内数的种数,问f(l,r)的期望

解法:sum(每个数算出他的贡献)/(n*n),我们这只考虑l<=r ,对于当前这数字他能贡献后面的所有区间,但是对于前面的话,他只共贡献到前一个相同的数后面 ,比如  1  2  3  4  2  5  6    对于第一个2  他贡献于  (1,2) (1,3)(1,4)(1,5)(1,6)(1,7)(2,2) (2,3)(2,4)(2,5)(2,6)(2,7)  对于第2个2  贡献于     (3,5)(3,6)(3,7)     (4,5)(4,6)(4,7)     (5,5)(5,6)(5,7)

#include <bits/stdc++.h>using namespace std;const int maxn = 1e6+10;typedef long long LL;int last[maxn];int main(){    int n,x;    LL ans = 0;    scanf("%d", &n);    for(int i=1; i<=n; i++){        scanf("%d", &x);        ans += 1LL*(i-last[x])*(n-i+1);        last[x]=i;    }    ans=ans*2-n;    printf("%.5f\n", ans*1.0/(1LL*n*n*1.0));    return 0;}


原创粉丝点击