Educational Codeforces Round 28 题解

比赛链接: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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值