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

    QAQ

    A. Display The Number

    思路:

    题目说了液晶屏最多有998244353位数,观察所有数字的液晶显示,只有1所用的线段最少,即使我们每一位都放1,最多也只有1e5/2位数,那么题目就变得简单了,我们优先凑一来增加所得数的位数,假如最后还剩下一根线段,我们可以把最高位变成7。

    代码:

    #include <bits/stdc++.h>
    using namespace std;
    int main()
    {
        int t;
        scanf("%d",&t);
        while(t--)
        {
            int n;
            scanf("%d",&n);
            int d = n/2;
            if(n%2==1)
                printf("7");
            else
                printf("1");
            for(int i = 1;i<d;++i)
                printf("1");
            printf("
    ");
        }
        return 0;
    }

    B. Infinite Prefixes

    思路:

    假设一个前缀ibalance值为pre[i],它的值可以表示为k*c+pre[i%n](其中c为一个串总的balance),对结果进行分类讨论。

    如果c0的话

    假如在一个s串中有值能达到x,则结果显然是无限的,否则,答案就是0

    如果c不是零的话,则可以枚举一个s的每个位置i,计算一下x = k*c+pre[i]是否存在整数k使方程成立,如果存在,则ans++

    代码:

    #include<bits/stdc++.h>
    
    using namespace std;
    
    typedef long long li;
    
    int n, x;
    string s;
    
    inline bool read() {
        if(!(cin >> n >> x >> s))
            return false;
        return true;
    }
    
    inline void solve() {
        int ans = 0;
        bool infAns = false;
        
        int cntZeros = (int)count(s.begin(), s.end(), '0');
        int total = cntZeros - (n - cntZeros);
        
        int bal = 0;
        for(int i = 0; i < n; i++) {
            if(total == 0) {
                if(bal == x)
                    infAns = true;
            }
            else if(abs(x - bal) % abs(total) == 0) {
                if((x - bal) / total >= 0)
                    ans++;
            }
            
            if(s[i] == '0')
                bal++;
            else
                bal--;
        }
        
        if(infAns) ans = -1;
        cout << ans << endl;
    }
    
    int main() {
        ios_base::sync_with_stdio(false);
        cin.tie(0), cout.tie(0);
        cout << fixed << setprecision(15);
        int tc; cin >> tc;
        while(tc--) {
            read();
            solve();
        }
        
        return 0;
    }

    C. Obtain The String

    思路:

    用一个set数组去存储s串每个字母出现的位置,从头遍历t串,另外用一个数记录下当前选用来构成z串所用字母的位置,假如在当前这次已经没有办法去找到符合条件的字母,那就代表需要在找一个s串来继续z串的填充,ans++,最后输出答案即可。

    代码:

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    set<int> st[30];
    int main()
    {
        int T;
        scanf("%d",&T);
        while(T--)
        {
            for(int i =0; i<26; i++)
                st[i].clear();
            //memset(tmp,0,sizeof(tmp));
            string s,t;
            cin >> s >> t;
            int len = s.size();
            for(int i = 0; i<len; ++i)
            {
                st[s[i]-'a'].insert(i);
            }
            len  =t.size();
            bool flag = false;
            LL ans =1;
            int tmp = 0;
            for(int i = 0; i<len; ++i)
            {
                int d = t[i]-'a';
                if(st[d].size()==0)
                {
                    flag = true;
                    break;
                }
                else
                {
                    set<int>::iterator it = st[d].lower_bound(tmp);
                    //cout << d << endl;
                    //cout << *it <<" " << tmp << endl;
                    if(it!=st[d].end())
                    {
                        tmp = (*it)+1;
                    }
                    else
                    {
                        ++ans;
                        tmp = 0;
                        --i;
                    }
                    //cout << "**" << ans << endl;
                }
            }
            if(flag)
            {
                printf("-1
    ");
            }
            else
                cout << ans << "
    ";
        }
        return 0;
    }

    D. Same GCDs

    思路:

    g = gcd(a,m)

    D题的答案就是Eular(m/g);证明如下,

     

     

    同时,因为

    所以变换之后a+x的取值区间就变成了[0,m)

    那么(a+x)/g的区间就是[0,m/g)

    整个式子就是求[0,m/g)中与m/g互素的数的个数,就是Eular(m/g)的值。

    代码:

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    LL Eular(LL n)
    {
        LL ans = n;
        for(LL i = 2;i*i<=n;++i)
        {
            if(n%i==0)
            {
                ans-=(ans/i);
                while(n%i==0)
                    n/=i;
            }
        }
        if(n>1) ans-=ans/n;
        return ans;
    }
    int main()
    {
        int T;
        cin >> T;
        while(T--)
        {
            LL a,b;
            cin >>a >> b;
            LL g = __gcd(a,b);
            cout << Eular(b/g) << endl;
        }
        return 0;
    }

    E. Permutation Separation

    思路:

    首先我们先假设分割的位置为i,长度为x,那么最终答案是多少?我们需要把1-x放进左边的集合,x+1-n放到右面的集合,所以总花费可以这样计算,令pos = x在原排列中的位置,对于i<=pos的部分来说,只要它的值比x大,它就需要移到右边,花费就需要加上这个数的权值。同样,对于i>pos的数来说,只要它的值比x小,他就需要移到左边,花费就需要加上它的权值。

    接下来我们考虑优化一下当前的算法。我们先求出前缀和pre,从x = 1.i = 1开始枚举,外层循环枚举x,内层循环枚举i,我们发现对于每个i<pos(x),答案都是pre[i]+a[pos(x)],而对于i>=pos(x),答案就变成了pre[i]-a[pos(x)],在x1的情况下就是上面两个式子所有取值的最小值。接下来x = 2,也是同样的道理,可以发现,事实上假如我们把前缀和作为节点的值建一棵线段树,上面的内层循环就变成的区间加上一个数以及求最小值。这样复杂度就由O(n^2)到了O(nlogn)。题目可解。

    代码:

    #include <bits/stdc++.h>
    using namespace std;
    #define MAXN 200000+10
    #define LL long long
    int n;
    int p[MAXN];
    int rp[MAXN];
    int a[MAXN];
    LL b[MAXN];
    long long t[4*MAXN];
    LL add[4*MAXN];
    void build(int v,int l,int r)
    {
        if(r-l==1)
        {
            t[v] = b[l];
            return ;
        }
        int mid = (l+r)/2;
        build(v*2+1,l,mid);
        build(v*2+2,mid,r);
        t[v] = min(t[v*2+1],t[v*2+2]);
        return ;
    }
    void push(int v,int l,int r)
    {
        if(add[v]!=0)
        {
            if(r-l>1)
            {
                for(int i = 2*v+1;i<2*v+3;++i)
                {
                    add[i]+=add[v];
                    t[i]+=add[v];
                }
            }
            add[v] = 0;
        }
    }
    void upd(int v,int l,int r,int L,int R,int x)
    {
        if(L>=R)
            return ;
        if(l==L&&r==R)
        {
            add[v]+=x;
            t[v]+=x;
            push(v,l,r);
            return ;
        }
        push(v,l,r);
        int mid = (l+r)/2;
        upd(v*2+1,l,mid,L,min(mid,R),x);
        upd(v*2+2,mid,r,max(L,mid),R,x);
        t[v] = min(t[v*2+1],t[v*2+2]);
    }
    void upd(int l,int r,int x)
    {
        upd(0,0,n,l,r,x);
    }
    LL get(int v,int l,int r,int L,int R)
    {
        if(L>=R)
            return 1e18;
            push(v,l,r);
        if(l==L&&r==R)
            return t[v];
        int mid = (l+r)/2;
        return min(get(v * 2 + 1, l, mid, L, min(R, mid)),
               get(v * 2 + 2, mid, r, max(L, mid), R));
    }
    LL get(int l,int r)
    {
        return get(0,0,n,l,r);
    }
    int main()
    {
        scanf("%d",&n);
        for(int i = 0;i<n;++i)
        {
            scanf("%d",p+i);
            --p[i];
            rp[p[i]] = i;
        }
        for(int i = 0;i<n;++i)
            scanf("%d",a+i);
        b[0] = a[0];
        for(int i = 1;i<n;++i)
            b[i] = a[i]+b[i-1];
        build(0,0,n);
        LL res = get(0,n-1);
        for(int i = 0;i<n;++i)
        {
            int pos = rp[i];
            upd(pos,n,-a[pos]);
            upd(0,pos,a[pos]);
            res = min(res,get(0,n-1));
        }
        cout <<res <<endl;
    
        return 0;
    }
  • 相关阅读:
    [Java基础] 深入jar包:从jar包中读取资源文件
    [Git] git merge和rebase的区别
    windows和linux中换行符的转换
    使用 scikit-learn 实现多类别及多标签分类算法
    python 特征缺失值填充
    多输出回归问题
    python DataFrame获取行数、列数、索引及第几行第几列的值
    Xgboost 模型保存和载入()
    pandas所占内存释放
    SSE,MSE,RMSE,R-square 指标讲解
  • 原文地址:https://www.cnblogs.com/baihualiaoluan/p/12291412.html
Copyright © 2011-2022 走看看