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

    Educational Codeforces Round 81 (Rated for Div. 2)

    A. Display The Number

    (n)个区域,问最大能构成的数字是多少?

    • (n)为奇数:(7111...)
    • (n)为偶数:(1111...)
    #include<bits/stdc++.h>
    #define mes(a, b) memset(a, b, sizeof a)
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    const int maxn = 2e5+10;
    const ll mod = 1e9+7;
    int n, m, T;
    int main(){
        scanf("%d", &T);
        while(T--){
            scanf("%d", &n);
            if(n % 2 == 1 )
                printf("7");
            else
                printf("1");
            int len = n/2-1;
            for(int i = 1; i <= len; i++)
                printf("1");
            printf("
    ");
        }
        return 0;
    }
    

    B. Infinite Prefixes

    给一个长度为(n)的字符串(s),字符串(t)是字符串(s)的无限循环。(cnt_0[q])表示在(0-q)之间有多少个(0)(cnt_1[q])表示在(0-q)之间有多少个(1)。问(cnt_0[q]-cnt_1[q] = x)中,(q)的个数。

    • 首先循环一遍求出(0-n)位置上的值,并且(a[n-1])为每次循环的变化。
    • (a[i] + a[n-1] * temp =x(tempge 0))则当前位置(i)肯定能有一次变为(x)
    • 如果(a[n-1]=0 && a[i] = x),那么则无限次。
    #include<bits/stdc++.h>
    #define mes(a, b) memset(a, b, sizeof a)
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    const int maxn = 2e5+10;
    const ll mod = 1e9+7;
    int n, m, T;
    int a[maxn];
    char ch[maxn];
    int main(){
        scanf("%d", &T);
        while(T--){
            scanf("%d%d", &n, &m);
            scanf("%s", ch+1);
            int len = strlen(ch+1), cnt = 0;
            for(int i = 1; i <= len; i++){
                if(ch[i] == '0')
                    a[i] = a[i-1]+1;
                else
                    a[i] = a[i-1]-1;
            }
            int flag = 0;
            if(a[len] == 0){
                for(int i = 1; i <= len; i++){
                    if(a[i] == m){
                        printf("-1
    ");
                        flag = 1;
                        break;
                    }
                }
                if(!flag)
                    printf("0
    ");
                continue;
            }
            int ans = 0;
            for(int i = 1; i <= len; i++){
                int x = (m-a[i])/a[len];
                if(x >= 0 && x *a[len] + a[i] == m)
                    ans++;
            }
            if(m == 0)
                ans++;
            printf("%d
    ", ans);
        }
        return 0;
    }
    

    C. Obtain The String

    给你字符串(s)和字符串(t),每次可以从字符串(s)中取出一个子序列加到当前字符串(z)的末尾,字符串(z)初始为空。问最少取几次,字符串(z)可以变成字符串(t)
    记录字符串(s)每个位置之后最近的每个字母的位置。暴力遍历即可。

    #include<bits/stdc++.h>
    #define mes(a, b) memset(a, b, sizeof a)
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    const int maxn = 2e5+10;
    const ll mod = 1e9+7;
    int n, m, T;
    char s[maxn], t[maxn];
    struct Node{
        int num[30];
    }a[maxn];
    int main(){
        scanf("%d", &T);
        while(T--){
            scanf("%s%s", s, t);
            int slen = strlen(s), tlen = strlen(t);
            mes(a[slen].num, -1);
            for(int i = slen-1; i >= 0; i--){
                int x = s[i] - 'a';
                a[i] = a[i+1];
                a[i].num[x] = i;
            }
            int ans = 0, cnt = 0;
            for(int i = 0; i < tlen; i++){
                int x = a[cnt].num[t[i]-'a'];
                if(x == -1){
                    x = a[0].num[t[i]-'a'];
                    if(x == -1){
                        ans = -1;
                        break;
                    }
                    else
                        ans++;
                }
                if(i == tlen-1)
                    ans++;
                cnt = x+1;
            }
            printf("%d
    ", ans);
        }
        return 0;
    }
    

    D. Same GCDs

    问在(nle xle n+m-1)中存在几个(x)(gcd(x, m) =gcd(n, m))

    • (Gcd = gcd(n, m)), 用唯一分解定理求出(m/Gcd)的质因子。
    • 用容斥定理算出(n/Gcdle x le (n+m-1)/Gcd)中为(m/Gcd)的质因子的倍数的个数(tmp)
    • 答案(ans = (n+m-1)/Gcd -(n-1)/Gcd -tmp)
      (感觉自己写的很麻烦不知道有没有简单一点的做法)
    #include<bits/stdc++.h>
    #define mes(a, b) memset(a, b, sizeof a)
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    const int maxn = 2e5+10;
    const ll mod = 1e9+7;
    ll n, m, ans, x;
    int  T, cnt, num[maxn], p[maxn];
    vector<ll> vec;
    ll gcd(ll a, ll b){
        return b == 0 ? a: gcd(b, a%b);
    }
    void init(){
        mes(num , 0);
        cnt = 0;
        for(ll i = 2; i < maxn; i++){
            if(!num[i]){
                p[++cnt] = i;
                for(ll j = i*i; j < maxn; j+=i){
                    num[j] = 1;
                }
            }
        }
    }
    void get(ll x){
        vec.clear();
        for(int i = 1; i <= cnt && p[i]*p[i] <= x; i++){
            if(x % p[i] == 0){
                vec.push_back(p[i]);
                while(x%p[i] == 0)
                    x /= p[i];
            }
        }
        if(x > 1)
            vec.push_back(x);
    }
    ll dfs(int pre, int pos, ll num){
        ll tmp;
        for(int i = pre; i < vec.size(); i++){
            tmp = num * vec[i];
            if(pos & 1)
                ans += x/tmp;
            else
                ans -= x/tmp;
            dfs(i+1, pos+1, tmp);
        }
    }
    int main(){
        scanf("%d", &T);
        init();
        while(T--){
            scanf("%lld%lld", &n, &m);
            int len = sqrt(m);
            ll Gcd = gcd(n, m);
            get(m/Gcd);
            ans = 0;
            x = (n+m-1)/Gcd;
            dfs(0, 1, 1);
            ll tmp = x - ans;
            x = (n-1)/Gcd;
            ans = 0;
            dfs(0, 1, 1);
            tmp -= (x-ans);
            printf("%lld
    ", tmp);
        }
        return 0;
    }
    

    E. Permutation Separation

    把一个长度为(n)数组(p),分为两个非空集合(p_1、p_2、p_3... p_k)(p_{k+1}、p_{k+2}...p_n),可以随意移动第一个集合的元素到第二个集合,也可以移动第二个集合的元素到第二个集合。移动元素(p_i)所需要的花费为(a_i)。问让第一个集合的元素小于任意一个第二个集合的元素(其中一个集合为空集也可满足条件),最小的花费是多少?
    首先能想到遍历所有的位置(k),从而找出最优解。那么要解决的问题是怎么在每次遍历的过程中快速的找到当前位置(k)的最优解。
    如果当前位置中,要让第一个集合小于数字(x),第二个集合数字大于(x),则花费为第一个集合大于(x)的数的花费+第二个集合小于(x)的数的花费。因为中间数字为(x),那么(x)在哪个集合都是成立的,则当前不用管数字(x)的花费。
    反过来说,如果数字(x)在第一个集合,而当前枚举的中间的数小于 (x)那么数字(x)肯定要移动到第二个集合。如果数字(x)在第二个集合,而当前枚举的中间的数大于 (x)那么数字(x)肯定要移动到第一个集合。
    那么数字(x)在第一个集合的时候会对中间数为([1,x-1])产生贡献。数字(x)在第二个集合的时候会对中间数为([x+1,n])产生贡献。

    • 可以用线段树来维护枚举每个位置为中间数的最小值。
    • (x)在第一个集合,把([1, x-1])的范围都加上(a_i)
    • (x)在第二个集合,把([x+1, n])的范围都加上(a_i)
    • 遍历每个位置(k)找出最小值
    #include<bits/stdc++.h>
    #define mes(a, b) memset(a, b, sizeof a)
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    const int maxn = 2e5+10;
    const ll mod = 1e9+7;
    int n;
    ll lazy[maxn<<2];
    ll node[maxn<<2], a[maxn];
    int p[maxn];
    void pushdown(int rt){
        if(lazy[rt]){
            node[rt<<1] += lazy[rt];
            node[rt<<1|1] += lazy[rt];
            lazy[rt<<1] += lazy[rt];
            lazy[rt<<1|1] += lazy[rt];
            lazy[rt] = 0;
        }
    }
    void update(int L, int R, ll c, int l, int r, int rt){
        if(R < L) return;
        if(L <= l && r <= R){
            node[rt] += c;
            lazy[rt] += c;
            return;
        }
        pushdown(rt);
        int mid = l+r>>1;
        if(L <= mid)
            update(L, R, c, l, mid, rt<<1);
        if(R > mid)
            update(L, R, c, mid+1, r, rt<<1|1);
        node[rt] = min(node[rt<<1], node[rt<<1|1]);
    }
    int main(){
        scanf("%d", &n);
        mes(node, 0);
        mes(lazy, 0);
        for(int i = 1; i <= n; i++)
            scanf("%d", &p[i]);
        for(int i = 1; i <= n; i++){
            scanf("%lld",&a[i]);
            update(p[i]+1, n, a[i], 1, n, 1);
        }
        ll ans = min(a[1], a[n]);
        for(int i = 1; i < n; i++){
            update(p[i]+1, n, -1*a[i], 1, n, 1);
            update(1, p[i]-1, a[i], 1, n, 1);
            ans = min(node[1], ans);
        }
        printf("%lld
    ", ans);
        return 0;
    }
    
  • 相关阅读:
    Python3 Selenium自动化web测试 ==> 第十一节 WebDriver高级应用 -- 显示等待 + 二次封装
    Python3 Selenium自动化web测试 ==>FAQ:Unittest测试报告生成文件名加测试完成时间字符串
    Python3 Selenium自动化web测试 ==>FAQ:日期格式和日期字符串格式相互转换
    学习目录
    dotnet学习系列
    Vue.js——60分钟browserify项目模板快速入门
    Vue.js——使用$.ajax和vue-resource实现OAuth的注册、登录、注销和API调用
    Vue.js——vue-resource全攻略
    Vue.js——基于$.ajax实现数据的跨域增删查改
    Vue.js——组件快速入门(下篇)
  • 原文地址:https://www.cnblogs.com/zhuyou/p/12242631.html
Copyright © 2011-2022 走看看