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
  • 相关阅读:
    无法直接启动带有类库输出类型的项目
    2个页面传值方法
    vs2005 无法附加 绑定句柄无效 解决办法
    认识serializable,序列化
    jsp 连接sql 2008
    有进步,嘎嘎....
    找不到存储过程'dbo.aspnet_CheckSchemaVersion'
    BackOffice Common中实现的相关功能
    MVC中Action相关方法的建议
    mysql的数据库相关维护操作:重启、修改连接数、删除连接
  • 原文地址:https://www.cnblogs.com/EchoZQN/p/12248967.html
Copyright © 2011-2022 走看看