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

    B. Infinite Prefixes

    题目大意:

    给你一个字符串s,s是一个01串,则t=ssss... 即为s的无限循环。

    问在无限长的字符串t中,有多少个前缀满足 : 0的个数 - 1的个数==x (x给出)

    思路:

    这个题目我开始以为是一个模拟题,这个就让我的方向上出现了很大的错误,

    我认为是模拟题,所以我想办法去模拟这个无限长的串,但没写出来。

    后来查了题解才发现是一个数学题。

    设bal(i) 表示前缀长度为 i 的0的个数 - 1的个数的值。

    对于研究有限长的 s 串,可以发现有两种情况。

    第一种就是 bal(n) == 0,也就是说s串0和1的个数相同,这个时候就判断一下是不是存在bal(i)==x

    如果存在,那么就输出 -1

    第二种情况是 bal(i)!=0 这个时候就是解一个方程 x==k*bal(n)+bal(i)

    从头往后遍历 判断对于每一个bal(i) 是否存在一个非负数 x==k*bal(n)+bal(i)

    为什么说只要遍历s串就可以了呢,t串可是包含了无数个s串的。

    这个很简单,因为s串之后都只是s串的简单的重复,这个说明bal(i)可以拆成 bal(i-n)+bal(n)

    只需要算s串即可,否则就会算重复了。

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=1e5+10;
    char s[maxn];
    int main(){
        int t;
        scanf("%d",&t);
        while(t--){
            int n,x;
            scanf("%d%d%s",&n,&x,s);
            int sum=0;
            for(int i=0;i<n;i++) {
                if(s[i]=='0') sum++;
                else sum--;
            }
            int flag=0,ans=0,cur=0;
            for(int i=0;i<n;i++){
                if(sum==0){
                    if(cur==x) flag=1;
                }
                else if(abs(x-cur)%sum==0){
                    if((x-cur)/sum>=0) ans++;
                }
                
                if(s[i]=='0') cur++;
                else cur--;
            }
            if(flag) ans=-1;
            printf("%d
    ",ans);
        }
        return 0;
    }
    B

    D. Same GCDs

    题目大意:给两个数 a,m 求gcd(a,m)==gcd(a+x,m) 并且 0<=x<m,求有多少个x满足条件。

    做法,有两种:

    第一种:

    因为gcd(a,m)==g  所以gcd(a+x,m)==g

    又因为a%g==0 (a+x)%g==0 所以 x%g==0

    gcd((a+x)/g,m/g)==1    a1=(a+x)/g,b1=m/g

    所以 a1的范围是[a/g,(a+m-1)/g]   b1 是一个常数,

    解决在一个区间内和b1互质的数的个数方法参见--->欧拉函数

    第二种:

    gcd(a+x,m)==gcd((a+x)%m,m)   a1=(a+x)%m

    所以a1的范围是[0,m-1]

    gcd(a1,m)==g 所以  gcd(a1/g,m/g)==1

    a2=a1/g  所以就相当于求欧拉函数

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=2e5+10;
    typedef long long ll;
    ll gcd(ll a,ll b){
        return b==0?a:gcd(b,a%b);
    } 
    int v[maxn],isp[maxn],m;
    void init1()
    {
        for(int i=2;i<maxn;i++){
            if(v[i]==0){
                isp[m++]=i;
                v[i]=i;
            }
            for(int j=0;j<m;j++){
                if(v[i]<isp[j]||i*isp[j]>maxn) break;
                v[i*isp[j]]=isp[j];
            }
        }
    }
    int main(){
        int t;
        init1();
        scanf("%d",&t);
        while(t--){
            ll a,b;
            scanf("%lld%lld",&a,&b);
            ll g=gcd(a,b);
            ll cur=b/g,lc=a/g,rc=(a+b-1)/g;
            for(int i=0;i<m;i++){
                int v=isp[i];
                if(cur%v==0){
                    lc=lc/v*(v-1),rc=rc/v*(v-1);
                    while(cur%v==0) cur/=v;
                }
            }
            if(cur!=1) lc=lc/cur*(cur-1),rc=rc/cur*(cur-1);
            printf("%lld
    ",rc-lc);
        }
        return 0;
    }
    View Code

    E. Permutation Separation

    题目大意:将一个序列进行划分,然后再进行交换,每一个数交换的代价为a[i],

    两种操作之后使得到的两段,第一段的数在区间[1,k] 第二段的数在区间[k+1,n],问最小的代价是多大?

    一开始没什么思路,然后问了lj才会写的。

    因为不同的划分位置会有不同的结果,所以我们一定要对划分的位置进行讨论,这样就有1e5的复杂度了。

    然后就是每一次划分我们都应该把最小代价求出。

    差不多就是这么做的把,自己再对着样例比划比划就可以写出来了。

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=2e5+10;
    typedef long long ll;
    //Ë㻨·Ñ×¢Ò⿪ long long
    ll mins[maxn*4],lazy[maxn*4],pre[maxn];
    ll p[maxn],a[maxn];
    void push_up(int id){
        mins[id]=min(mins[id<<1],mins[id<<1|1]);
    }
    void build(int id,int l,int r){
        lazy[id]=0;
        if(l==r){
            mins[id]=pre[l];
            return ;
        }
        int mid=(l+r)>>1;
        build(id<<1,l,mid);
        build(id<<1|1,mid+1,r);
        push_up(id);
    }
    void push_down(int id){
        if(lazy[id]==0) return ;
        mins[id<<1]+=lazy[id];
        mins[id<<1|1]+=lazy[id];
        lazy[id<<1]+=lazy[id];
        lazy[id<<1|1]+=lazy[id];
        lazy[id]=0;
    }
    void update(int id,int l,int r,int x,int y,ll val){
        if(x>r||y<l) return ;
        if(x<=l&&y>=r){
            mins[id]+=val;
            lazy[id]+=val;
            return ;
        }
        push_down(id);
        int mid=(l+r)>>1;
        if(x<=mid) update(id<<1,l,mid,x,y,val);
        if(y>mid) update(id<<1|1,mid+1,r,x,y,val);
        push_up(id);
    }
    int main(){
        int n;
        scanf("%d",&n);
        for(int i=1;i<=n;i++) scanf("%lld",&p[i]);
        for(int i=1;i<=n;i++) scanf("%lld",&a[i]),pre[p[i]]=a[i];
        for(int i=1;i<=n;i++) pre[i]=pre[i]+pre[i-1];
        build(1,1,n);    
        ll ans=min(a[1],a[n]);
        for(int i=1;i<n;i++){
            update(1,1,n,1,p[i]-1,a[i]);
            update(1,1,n,p[i],n,-a[i]);
            ans=min(ans,mins[1]);
    //        printf("i=%d ans=%lld
    ",i,ans);
        }
        printf("%lld
    ",ans);
        return 0;
    }
    E
  • 相关阅读:
    赫尔维茨公式
    从解析几何的角度分析二次型
    Struts 1 Struts 2
    记一次服务器被入侵的调查取证
    契约式设计 契约式编程 Design by contract
    lsblk df
    Linux Find Out Last System Reboot Time and Date Command 登录安全 开关机 记录 帐号审计 历史记录命令条数
    Infrastructure for container projects.
    更新文档 版本控制 多版本并发控制
    Building Microservices: Using an API Gateway
  • 原文地址:https://www.cnblogs.com/EchoZQN/p/12248967.html
Copyright © 2011-2022 走看看