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\n",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\n",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\n",i,ans);
    }
    printf("%lld\n",ans);
    return 0;
}
E

 

posted @ 2020-02-01 16:40  EchoZQN  阅读(229)  评论(0编辑  收藏  举报