zoukankan      html  css  js  c++  java
  • Educational Codeforces Round 103 (Rated for Div. 2)

    Educational Codeforces Round 103 (Rated for Div. 2)

    A. K-divisible Sum

    Problem:

      给定 n 和 k,请问使 n 个正整数的和可以整除 k 时,n 个数中最大的数最小是多少?

      (a1 + a2 + a3 + .... + an) % k == 0 时,使max(a1,a2,a3,....,a4) 最小

    Solution:

      很明显,n 个数最小能的和就是 n ,所以首先我们需要求出 k * i >= n 时最小的 i 是多少,然后让 (k * i / n)向上取整就是答案。(要让最大的数最小,很明显就是将需要求得的和尽可能被平分,要是不能平分则将会导致最大的数比能够平分的数大 1 )(n = 4,k * i  = 10,10 = 2 + 2 + (2 + 1) + (2 + 1))

    #include<bits/stdc++.h>
    #define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
    #define _for(i,s,t) for(int i=s;i<t;i++)
    #define _rof(i,s,t) for(int i=s;i>t;i--)
    #define rep(i,s,t) for(int i=s;i<=t;i++)
    #define per(i,s,t) for(int i=s;i>=t;i--)
    #define Ri(x) scanf("%d",&x)
    #define Rii(x,y) scanf("%d%d",&x,&y)
    #define INF 0x3f3f3f3f
    using namespace std;
    template<class T>inline void read(T &res)
    {
        char c;T flag=1;
        while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;res=c-'0';
        while((c=getchar())>='0'&&c<='9')res=res*10+c-'0';res*=flag;
    }
    typedef long long ll;
    const int maxn = 1e5 + 10;
    int main(){
        IOS;
        int t,n,k;
        cin>>t;
        while(t--){
            cin>>n>>k;
            if(n > k){
                k = ceil(n*1.0 / k) * k;
            }
            if(n == 1){
                cout<<k<<endl;
                continue;
            }
            cout<<(int)ceil(k*1.0/n)<<endl;
        }
        return 0;
    }
    View Code

    B. Inflation

    Problem:

      给的 n 和 k,有 n 个数 p0,p1,p2,p(n-1),问在允许对 pi 进行增加时,如何在能保证(p[ i ] /(p[ 1 ] + ..... + p[ i - 1 ])<= 1 / k)的情况下, 最少需要增加 pi 多少值。

    Solution:

      我们从头计算,遇到不满足式子的就增加其分母到刚好满足的情况就好了,最终计算每次增加的和就是答案。注意在计算增加多少时可能无法让式子两边一定相等,所以需要对其进行向上取整,保证一定满足小于等于。

    #include<bits/stdc++.h>
    #define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
    #define _for(i,s,t) for(int i=s;i<t;i++)
    #define _rof(i,s,t) for(int i=s;i>t;i--)
    #define rep(i,s,t) for(int i=s;i<=t;i++)
    #define per(i,s,t) for(int i=s;i>=t;i--)
    #define Ri(x) scanf("%d",&x)
    #define Rii(x,y) scanf("%d%d",&x,&y)
    #define INF 0x3f3f3f3f
    using namespace std;
    template<class T>inline void read(T &res)
    {
        char c;T flag=1;
        while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;res=c-'0';
        while((c=getchar())>='0'&&c<='9')res=res*10+c-'0';res*=flag;
    }
    typedef long long ll;
    const int maxn = 1e2 + 10;
    ll p[maxn];
    int main(){
        IOS;
        ll t,n,k;
        cin>>t;
        while(t--){
            cin>>n>>k;
            rep(i,1,n){
                cin>>p[i];
                p[i] = p[i];
            }
            ll sum = p[1],ans = 0,tmp = 0;
            rep(i,2,n){
                if(p[i]*100 > k * 1ll * sum){
                    tmp = ceil(p[i]*1.0 * 100 / k - sum);
                    ans += tmp;
                    sum += tmp;
                }
                sum += p[i];
            }
            cout<<ans<<endl;
        }
        return 0;
    }
    View Code

    C. Longest Simple Cycle

    Problem:

      给定 n 条链,每一条链上面有 c[ i ] 个点(点的编号为 1 ~ c[ i ]),每一条链上面的第一个点会连接前一条边的 a[ i ] 点,最后一个点会连接前一条边的 b[ i ] 点,问最长的环是多长?环是一个链,其中第一个顶点和最后一个顶点也是连接的。如果你沿着这个环运动,这个环的每个顶点都会恰好到达一次

    Solution:

      由于每个链都是第一个点和最后一个点和前一条的点相连,所以第一条链是连接不到前面的,最后一条边是不会被别人连接的。

      由此我们可以知道形成环会出现以下几种情况:

        (1)相邻两条链构成环,那么长度就是 | a - b | + c + 2 (其中 a 和 b 是当前链连接前面链的点的编号,c 是当前链的长度,2 是连接时候的两条边)

        (2)多条链构成环,由于是多条链,所以除去第一条和最后一条以外,中间的链所贡献的长度都是 min(a,b) - 1 + c - max(a,b) (a,b是被连接的点,c是当前边的长度)。不过由于我们可能会遇到丢弃前面多条链,只保留当前链,出现这种情况是因为前面多条链贡献的长度小于当前链的 | a - b | 的长度。(注意:在讨论时,我们都是以保留了我们当前多条链中的最后一条链为前提,这样才能保证可以形成环)

      编程:首先第一条链的贡献值为 | a - b |,然后我们从第二条开始往后遍历,遍历到第 i 条链时。

         若 ai == bi,则表示我们需要丢弃前面计算出的长度,将当前环的长度变成 2 ,因为当前第 i 条链连接了第 i - 1 条链的同一个点;

         若 ai != bi ,设当前未连接第 i 条链时,当前环的长度为 res,当前最大的答案为ans,那么我们需要更新

           res = max(res + a[ i ] - 1 + c[ i - 1 ] - b[ i ],| a[ i ] - b[ i ] |);

             (res + a[ i ] - 1 + c[ i - 1 ] - b[ i ]):表示的是环继续沿着链走,| a[ i ] - b[ i ] |:表示的是环丢弃前面的链,只保留第 i - 1 条链。

           ans = max(ans,res + c[ i ] - 1 + 2);

             (res + c[ i ] - 1 + 2):表示以当前链为最后一条链形成环时的长度

    #include<bits/stdc++.h>
    #define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
    #define _for(i,s,t) for(int i=s;i<t;i++)
    #define _rof(i,s,t) for(int i=s;i>t;i--)
    #define rep(i,s,t) for(int i=s;i<=t;i++)
    #define per(i,s,t) for(int i=s;i>=t;i--)
    #define Ri(x) scanf("%d",&x)
    #define Rii(x,y) scanf("%d%d",&x,&y)
    #define INF 0x3f3f3f3f
    using namespace std;
    template<class T>inline void read(T &res)
    {
        char c;T flag=1;
        while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;res=c-'0';
        while((c=getchar())>='0'&&c<='9')res=res*10+c-'0';res*=flag;
    }
    typedef long long ll;
    const int maxn = 1e5 + 10;
    ll a[maxn],b[maxn],c[maxn];
    int main(){
        IOS;
        int t,n;
        cin>>t;
        while(t --){
            cin>>n;
            rep(i,1,n){
                cin>>c[i];
            }
            rep(i,1,n){
                cin>>a[i];
            }
            rep(i,1,n){
                cin>>b[i];
            }
            if(a[1] > b[1]) swap(a[1],b[1]);
            ll ans = 0,res = 0;
            rep(i,2,n){
                if(a[i] > b[i]) swap(a[i],b[i]);
                if(a[i] == b[i]){
                    ans = max(ans,res);
                    ans = max(ans,c[i] - 1 + 2);
                    res = 0;
                }else{
                    if(i - 1 == 1){
                        res += b[i] - a[i];
                    }else{    
                        res += a[i] - 1 + c[i - 1] - b[i];
                        res = max(res,b[i] - a[i]);
                    }
                    ans = max(ans,res + c[i] - 1 + 2);
                }
                res += 2;
            }
            res += c[n] - 1;
            ans = max(ans,res);
            cout<<ans<<endl;
        }
        return 0;
    }
    View Code

    D. Journey

    Problem:

       给你长度为 n 的字符串s,字符串中只有 L 和 R 两种字符,s[ i ] = 'L' 表示存在一条 i + 1 到 i 的边,s[ i ] = 'R' 表示存在一条 i 到 i + 1 的边。当一个人从一个点到另一个点后,所有的边的方向都会反向一次,问从每个点出发,最多能到达几个点(可以经过一个点多次)。

    Solution:

      先计算每个点只能向左走能经过几个点,然后计算每个点只能向右走能经过几个点,最终答案就是向左的加上向右的。

      设 num[ i ] = j 表示第 i 个点能到达几个点,初始化所有值为 1(此处需要定义 numl 和 numr 两个数组)

      计算每个点只能向左走能经过几个点,我们从前往后遍历这 n + 1 个点(从 2 遍历到 n + 1),若 i 到 i - 1 有边的时候,我们numr[ i ] += 1,若 (i 到 i - 1有边 && i - 2 到 i - 1有边)则numr[ i ] += numr[i - 2]

      计算每个点只能向右走能经过几个点,我们从后往前遍历(从 n 遍历到 1),若 i 到 i + 1 有边的时候,我们numl[ i ] += 1,若 (i 到 i + 1有边 && i + 2 到 i + 1有边)则numl[ i ] += numl[i + 2]

      最终numl[ i ] + numr[ i ] - 1就是第 i 个点的答案。

    #include<bits/stdc++.h>
    #define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
    #define _for(i,s,t) for(int i=s;i<t;i++)
    #define _rof(i,s,t) for(int i=s;i>t;i--)
    #define rep(i,s,t) for(int i=s;i<=t;i++)
    #define per(i,s,t) for(int i=s;i>=t;i--)
    #define Ri(x) scanf("%d",&x)
    #define Rii(x,y) scanf("%d%d",&x,&y)
    #define INF 0x3f3f3f3f
    using namespace std;
    template<class T>inline void read(T &res)
    {
        char c;T flag=1;
        while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;res=c-'0';
        while((c=getchar())>='0'&&c<='9')res=res*10+c-'0';res*=flag;
    }
    typedef long long ll;
    const int maxn = 3e5 + 10;
    int numr[maxn],numl[maxn];
    char s[maxn];
    int main(){
        IOS;
        int t,n;
        cin>>t;
        while(t --){
            cin>>n;
            cin>>(s + 1);
            numr[1] = 1;
            rep(i,2,n + 1){
                numr[i] = 1;
                if(s[i - 1] == 'L') numr[i] += 1;
                if(i - 2 >= 1 && s[i - 1] == 'L' && s[i - 2] == 'R') numr[i] += numr[i - 2]; 
            }
            numl[n + 1] = 1;
            per(i,n,1){
                numl[i] = 1;
                if(s[i] == 'R') numl[i] += 1;
                if(i + 1 <= n && s[i] == 'R' && s[i + 1] == 'L') numl[i] += numl[i + 2]; 
            }
            rep(i,1,n + 1){
                cout<<(numr[i] + numl[i] - 1)<<" ";
            }
            cout<<endl;
        }
        return 0;
    }
    View Code

    补题 D

    E、F、G 略

     

  • 相关阅读:
    USACO2018 DEC(Platinum) (树上乱搞,期望+凸包)
    USACO2018 DEC (Gold) (dp,容斥+哈希,最短路)
    《信息学奥赛一本通》题库 1034 计算三角形面积——基础
    UNR#3 Day1——[ 堆+ST表+复杂度分析 ][ 结论 ][ 线段树合并 ]
    bzoj 4298 [ONTAK2015]Bajtocja——哈希+启发式合并
    玲珑杯#20 C 漆黑的太阳——莫队
    链表写法
    传址函数写法
    bzoj 4650 & 洛谷 P1117 优秀的拆分 —— 枚举关键点+后缀数组
    bzoj 2119 股市的预测 —— 枚举关键点+后缀数组
  • 原文地址:https://www.cnblogs.com/liuzuolin/p/14353655.html
Copyright © 2011-2022 走看看