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 略

 

posted @ 2021-01-31 19:37  Choose_and_be_chosen  阅读(40)  评论(0编辑  收藏  举报