• COCI2014-2015 Contest#1 题目选做


    COCI2014-2015 Contest#1 题目选做

    A.PROSJEK

    Description

    有一个数列 a,现在按照下列公式求出一个数列  $ b_i  = frac{{}sum_{j = 1}^{i}a_i}{i} $

    给你数列 b,请求出数列 a

    Solution

    显然通过b预处理出前缀和直接搞定

    #include<bits/stdc++.h>
    
    using namespace std;
    
    inline int read()
    {
        int f = 1,x = 0;
        char ch;
        do
        {
            ch = getchar();
            if(ch == '-') f = -1;
        }while(ch < '0'||ch > '9');
        do
        {
            x = (x<<3) + (x<<1) + ch - '0';
            ch = getchar();
        }while(ch >= '0'&&ch <= '9');
        return f*x;
    }
    
    const int MAXN = 100 + 10;
    
    long long sum[MAXN]; 
    
    int main()
    {
        int n = read();
        for(int i=1;i<=n;i++)
        {
            int x  = read();
            sum[i] = 1LL * x * i;
        }
        for(int i=1;i<=n;i++) printf("%lld ",sum[i] - sum[i-1]);
    }
    View Code

    B.KLOPKA

    Description

    在平面直角坐标系上有 n 个点。

    现在要用一个正方形将点框起来,使得每一个点都能在正方形的内部或边上。要求这个正方形的边平行于坐标轴。

    求出这个正方形的最小面积。

    Solution

    记录一下横纵坐标最大最小值即可

    #include<bits/stdc++.h>
    
    using namespace std;
    
    inline int read()
    {
        int f = 1,x = 0;
        char ch;
        do
        {
            ch = getchar();
            if(ch == '-') f = -1;    
        }while(ch < '0'||ch > '9');
        do
        {
            x = (x<<3) + (x<<1) + ch - '0';
            ch = getchar();    
        }while(ch >= '0'&&ch <= '9');
        return f*x; 
    } 
    
    const int MAXN = 20 + 10;
    
    int n;
    int x[MAXN],y[MAXN];
    int maxx,maxy,minx,miny;
    
    int main()
    {
        n = read();
        minx = 1<<30,miny = 1<<30;
        for(int i=1;i<=n;i++)
        {
            x[i] = read(),y[i] = read();
            maxx = max(maxx,x[i]);
            maxy = max(maxy,y[i]);
            minx = min(minx,x[i]);
            miny = min(miny,y[i]);
        }
        cout << max((maxx - minx)*(maxx - minx),(maxy - miny) * (maxy - miny)) << endl;
    }
    View Code

    D.MAFIJA

    Description

    n 个人,其中有一些人是平民,有一些人是坏蛋。

    现在,平民们想揪出所有的坏蛋,于是 n 个人都指认了一个人是坏蛋。

    如果一个人是平民,他会随便乱指认,否则,他会指认一个平民。

    求出最多的坏蛋个数。

    Solution

    把指认的关系当做边连边,把坏蛋当做染成1,好人当做染成0

    由于坏蛋不能连坏蛋,与1相连的点一定为0

    假如是一条链的话,显然交叉染色,从链尾开始染更优

    把链扩展成树,发现每次把入度为0的点染成1一定最优

    但是实际上有可能出现环

    考虑为环的情况,如果环上的点都没有限制,显然随便选一个点染成0,这个点两边染色就没有限制了,就断成链了

    考虑环上的点有限制的情况,即为基环树的情况

    还是从入度为0的点开始染,环上有点被确定染成了0那么这个环显然就被断成链了,就按找链的方式贪心即可

    所以可以设计出这样一个贪心算法

    每次把入度为0且没有确定下来的点染成1,这样最后剩下的一定是几个独立的环

    每次随便选环上一点染成0,把环断成链即可

    #include<bits/stdc++.h>
    
    using namespace std;
    
    inline int read()
    {
        int f = 1,x = 0;
        char ch;
        do
        {
            ch = getchar();
            if(ch == '-') f = -1;
        }while(ch < '0'||ch > '9');
        do
        {
            x = (x<<3) + (x<<1) + ch - '0';
            ch = getchar();
        }while(ch >= '0'&&ch <= '9');
        return f*x;
    }
    
    const int MAXN = 5e5 + 10;
    
    int n;
    int a[MAXN];
    int deg[MAXN]; 
    bool vis[MAXN];
    int ans;
    
    inline void dfs(int x,int col)
    {
        if(vis[x]) return;
        vis[x] = 1; 
        ans += col;
        deg[a[x]]--;
        if((!deg[a[x]])||col == 1) dfs(a[x],col^1);
    }
    
    int main()
    {
        n = read();
        for(int i=1;i<=n;i++) a[i] = read(),deg[a[i]]++;
        for(int i=1;i<=n;i++) if(!deg[i]) dfs(i,1);
        for(int i=1;i<=n;i++) if(!vis[i]) dfs(i,0);
        cout << ans << endl;
    }
    View Code

    E.ZABAVA

    Description

    一座新的公寓开放了,这座公寓有 m 栋楼。

    现在会有 n 个学生,每一天都会进来一个人。

    一栋楼进来一个人后,会进行一场派对,派对会有与当前人数相等的吵闹指数。

    但是,现在可以进行 k 次操作,每一次操作可以将一栋楼里的全部学生踢出这座新公寓。

    请注意,学生先进楼,然后才能进行操作。

    现在求出最小吵闹指数的相加之和。

    你不必使用完全部的操作。

    Solution

    注意到每座公寓是独立的

    每个公寓对答案的贡献只和分了几次有关

    这就是背包问题

    考虑如何计算每个公寓分X次的最小吵闹和

    容易发现人数是一定,要最小化答案一定是尽量均分

    #include<bits/stdc++.h>
    
    using namespace std;
    
    inline int read()
    {
        int f = 1,x = 0;
        char ch;
        do
        {
            ch = getchar();
            if(ch == '-') f = -1;
        }while(ch < '0'||ch > '9');
        do
        {
            x = (x<<3) + (x<<1) + ch - '0';
            ch = getchar();
        }while(ch >= '0'&&ch <= '9');
        return f*x;
    }
    
    const int MAXN = 500 + 10;
    
    long long n,m,k;
    long long p[MAXN];
    long long f[MAXN][MAXN];
    
    inline long long calc(long long x,long long K)
    {
        long long val = x/K;
        long long num1 = (val+1) * K - x;
        long long  num2 = K - num1;
        return num2 * (val + 1) * (val + 2)/2 + num1 * val * (val + 1)/2;
    }
    
    int main()
    {
        n = read(),m = read(),k = read();
        for(int i=1;i<=n;i++)
        {
            int x = read();
            p[x]++;
        }
        memset(f,0x3f,sizeof(f));
        for(int j=0;j<=k;j++) f[0][j] = 0;
        for(int i=1;i<=m;i++)
        {
            for(int j=0;j<=k;j++)
            {
                for(int h=0;h<=j;h++)
                {
                    int l = j - (h);
                    f[i][j] = min(f[i][j],f[i-1][h] + calc(p[i],l+1));
                }
            }
        }
        cout << f[m][k] << endl;
    }
    View Code

    F.Kamp

    Description

    一颗树 n 个点,n−1 条边,经过每条边都要花费一定的时间,任意两个点都是联通的。

    K 个人(分布在 K 个不同的点)要集中到一个点举行聚会。

    聚会结束后需要一辆车从举行聚会的这点出发,把这 K 个人分别送回去。

    请你回答,对于 i=1∼n,如果在第 i个点举行聚会,司机最少需要多少时间把 K 个人都送回家

    Solution

    很简单的换根DP

    考虑到以X为根的答案,相当于X的子树中的答案,以及它到子树外的答案减掉可以省下的最大距离

    就维护一下就没了

    #include<bits/stdc++.h>
    
    using namespace std;
    
    inline int read()
    {
        int f = 1,x = 0;
        char ch;
        do
        {
            ch = getchar();
            if(ch == '-') f = -1;
        }while(ch < '0'||ch > '9');
        do
        {
            x = (x<<3) + (x<<1) + ch - '0';
            ch = getchar();
        }while(ch >= '0'&&ch <= '9');
        return f*x;
    }
    
    const int MAXN = 500000 + 10;
    
    int n,k;
    vector<pair<int,int> >G[MAXN];
    int a[MAXN],sz[MAXN];
    long long f[MAXN],g[MAXN],h[MAXN];
    long long dis1[MAXN],dis2[MAXN];
    
    inline void dfs(int x,int ff)
    {
        sz[x] += a[x];
        for(int i=0;i<G[x].size();i++)
        {
            int v = G[x][i].first;
            if(v == ff) continue;
            dfs(v,x);
            sz[x] += sz[v];
            if(sz[v])
            {
                f[x] += (f[v] +  2 * (G[x][i].second));
                long long w = G[x][i].second;
                if(dis1[x] < dis1[v] + w) 
                {
                    dis2[x] = dis1[x];
                    dis1[x] = dis1[v] + w; 
                }
                else if(dis2[x] < dis1[v] + w) dis2[x] = dis1[v] + w;
            }
        }
    }
    
    inline void dp(int x,int ff)
    {
        for(int i=0;i<G[x].size();i++)
        {
            int v = G[x][i].first;
            if(v == ff) continue;
            if(sz[v] == k)
            {
                dp(v,x);
                continue;
            }
            g[v] = g[x] + (f[x] - f[v]);
            long long w = G[x][i].second;
            if(!sz[v]) g[v] += 2 * ( G[x][i].second);
            if(dis1[v]+w == dis1[x]) h[v] = max(h[x] , dis2[x]) + w;
            else h[v] = max(h[x],dis1[x]) + w;
            dp(v,x);
        }
    }
    
    int main()
    {
        n  = read(),k = read();
        for(int i=1;i<n;i++)
        {
            int a = read(),b = read(),c = read();
            G[a].push_back(make_pair(b,c));
            G[b].push_back(make_pair(a,c)); 
        }
        for(int i=1;i<=k;i++) a[read()]++;
        dfs(1,0);
        //cout << 1 << endl;
        dp(1,0);
        for(int i=1;i<=n;i++) printf("%lld
    ",f[i] + g[i] - max(dis1[i] , h[i]));
    }
    View Code
  • 相关阅读:
    maven的.m2文件夹
    maven parent.relativePath
    GoLang structTag说明
    Mac下如何用SSH连接远程Linux服务器
    String.split
    Laya 类列表加载优化
    JavaEE JDBC 了解数据库连接池
    JavaEE JDBC 了解JNDI
    JavaEE JDBC 事务
    JavaEE JDBC RowSet行集
  • 原文地址:https://www.cnblogs.com/wlzs1432/p/13864339.html
Copyright © 2020-2023  润新知