Codeforces Round #361 (Div. 2)题解

来源:互联网 发布:c语言竖线是什么符号 编辑:程序博客网 时间:2024/05/29 08:26

  这套题比上一套题水多了,但是写题解真的好累啊啊啊啊啊!!!

  Div. 2
  

Div. 2 A Mike and Cellphone

  这题只需要把拨的号码上下左右移动一下看有没有超出键盘范围就好了。

#include<bits/stdc++.h> int main(){    int n,i,j,x;    char c;    bool flag[6][5],flag1[6][5],flag2=true;    memset(flag,false,sizeof(flag));    memset(flag1,false,sizeof(flag1));    for (i=1;i<=3;i++)        for (j=1;j<=3;j++)            flag[i][j]=true;    flag[4][2]=true;    scanf("%d",&n);    getchar();    for (i=0;i<n;i++)    {        c=getchar();        x=c-'0';        if (x)            flag1[(x-1)/3+1][(x-1)%3+1]=true;        else            flag1[4][2]=true;    }    for (i=0;i<6;i++)        for (j=0;j<5;j++)            if (flag1[i][j])                if (!flag[i+1][j])                {                    flag2=false;                    break;                }     if (flag2)    {        printf("NO");        return 0;    }    flag2=true;    for (i=0;i<6;i++)        for (j=0;j<5;j++)            if (flag1[i][j])                if (!flag[i-1][j])                {                    flag2=false;                    break;                }     if (flag2)    {        printf("NO");        return 0;    }flag2=true;    for (i=0;i<6;i++)        for (j=0;j<5;j++)            if (flag1[i][j])                if (!flag[i][j+1])                {                    flag2=false;                    break;                }     if (flag2)    {        printf("NO");        return 0;    }    flag2=true;    for (i=0;i<6;i++)        for (j=0;j<5;j++)            if (flag1[i][j])                if (!flag[i][j-1])                {                    flag2=false;                    break;                }     if (flag2)    {        printf("NO");        return 0;    }    printf("YES");    return 0;}

Div. 2 B Mike and Shortcuts

  这道题等价于,给一棵无向树,其中仅有(i,i+1)(i,i1)(i,a i ) 之间有边,所有边的权为1,求编号为1的点到其余各点的最短路程。直接SPFA 就好了。复杂度O(n) 

#include<bits/stdc++.h>#define N 200010using namespace std;queue<int>q;typedef struct edge{    int next,to;};typedef struct point{    int first,dis,visited;};edge edg[3*N];point poi[N];int e;void addedge(int u,int v){    edg[++e].to=v;    edg[e].next=poi[u].first;    poi[u].first=e;}void dfs(int i){    int j;    poi[i].visited=true;    for (j=poi[i].first;j;j=edg[j].next)    {        if (poi[edg[j].to].dis>poi[i].dis+1)        {            poi[edg[j].to].dis=poi[i].dis+1;            q.push(edg[j].to);        }        if (!poi[edg[j].to].visited)            dfs(edg[j].to);    }}void bfs(){    int i,j;    while (!q.empty())    {        for (i=q.front(),q.pop(),j=poi[i].first;j;j=edg[j].next)            if (poi[edg[j].to].dis>poi[i].dis+1)            {                q.push(edg[j].to);                poi[edg[j].to].dis=poi[i].dis+1;            }    }}int main(){    int n,i,a;    scanf("%d",&n);    for (i=1;i<=n-1;i++)    {        addedge(i,i+1);        addedge(i+1,i);    }    for (i=1;i<=n;i++)    {        poi[i].dis=i-1;        poi[i].visited=false;    }    for (i=1;i<=n;i++)    {        scanf("%d",&a);        if (i!=a)            addedge(i,a);    }    dfs(1);    bfs();    for (i=1;i<=n;i++)        printf("%d ",poi[i].dis);    return 0;}

Div. 2 C Mike and Shortcuts

  一道数论题,对于每个n ,符合要求的方案数为  i=2 [ni 3  ] ,显然这是一个增函数,所以我们可以二分答案。复杂度O(m − −   3 logm) 

#include<bits/stdc++.h>using namespace std;long long total(long long mid){    long long sum=0,i;    for (i=2;mid/(i*i*i);i++)        sum+=mid/(i*i*i);    return sum;}int main(){    long long i,left,right,mid,m;    scanf("%I64d",&m);    left=0;    right=m<<3;    while (left<right-1)    {        mid=(left+right)/2;        if (total(mid)>=m)            right=mid;        else            left=mid;    }    if (total(left)==m)        printf("%I64d",left);    else        if (total(right)==m)            printf("%I64d",right);    else        printf("-1");    return 0;}

Div. 2 D Friends and Subsequences

  固定l 之后,关于r ,最大值递增,最小值递减,所以我们可以二分答案,具体实现时用两棵线段树分别维护最大、最小值。复杂度O(nlog 2 n) 

#include<bits/stdc++.h>using namespace std;const int N=1<<18;int segmax[2*N],segmin[2*N],n,a[N],b[N];void buildmax(){    int i;    for (i=N+n-1;i>=N;i--)        segmax[i]=a[i-N+1];    for (i=N-1;i>=1;i--)        segmax[i]=max(segmax[i*2],segmax[i*2+1]);}void buildmin(){    int i;    for (i=N+n-1;i>=N;i--)        segmin[i]=b[i-N+1];    for (i=N-1;i>=1;i--)        segmin[i]=min(segmin[i*2],segmin[i*2+1]);}int searchmax(int left,int right){    int m=INT_MIN,l,r;    for (l=N+left-1,r=N+right;l<r;l/=2,r/=2)    {        if (l%2)            m=max(m,segmax[l++]);        if (r%2)            m=max(m,segmax[--r]);    }    /*cout<<left<<" max "<<right<<endl;    cout<<m<<endl;*/    return m;}int searchmin(int left,int right){    int m=INT_MAX,l,r;    for (l=N+left-1,r=N+right;l<r;l/=2,r/=2)    {        if (l%2)            m=min(m,segmin[l++]);        if (r%2)            m=min(m,segmin[--r]);    }    /*cout<<left<<" min "<<right<<endl;    cout<<m<<endl;*/    return m;}int main(){    int i,j,l,r,mid,left,right;    long long ans=0;    scanf("%d",&n);    for (i=1;i<=n;i++)        scanf("%d",&a[i]);    for (i=1;i<=n;i++)        scanf("%d",&b[i]);    for (i=1;i<N<<1;i++)    {        segmax[i]=INT_MIN;        segmin[i]=INT_MAX;    }    buildmax();    buildmin();    for (i=1;i<=n;i++)    {        l=i;        r=n;        while (l<r)        {            mid=(l+r)/2+1;            if (searchmax(i,mid)<searchmin(i,mid))                l=mid;            else                r=mid-1;        }        if (searchmax(i,l)>=searchmin(i,l))            l--;        left=l;        //cout<<left<<endl;        l=i;        r=n;        while (l<r)        {            mid=(l+r)/2;            if (searchmax(i,mid)>searchmin(i,mid))                r=mid;            else                l=mid+1;        }        if (searchmax(i,l)<=searchmin(i,l))            l++;        right=l;        //cout<<right<<endl;        ans+=right-left-1;    }    printf("%I64d",ans);    return 0;}

Div. 2 E Mike and Geometry Problem

  首先用前缀和的方法来统计各点被覆盖的次数,然后把200000以内的阶乘和阶乘的数论倒数打个表用来计算组合数就好了。注意用费马小定理求数论倒数时直接硬算会超时,要用快速幂。复杂度O(nlogn) 

#include<bits/stdc++.h>using namespace std;map<long long,long long>m;const long long N=200010;const long long moder=1000000007;long long n,l[N],r[N],k,fac[N],inv[N];long long power(long long num,long long index){    long long i,j,bi[40],ans=1;    i=0;    while (index)    {        bi[i++]=index%2;        index/=2;    }    for (j=0;j<i;j++)    {        if (bi[j])            ans=ans*num%moder;        num=num*num%moder;    }    return ans;}int main(){    long long i,k,count=0,ans=0,pre;    scanf("%I64d%I64d",&n,&k);    for (i=0;i<n;i++)    {        scanf("%I64d%I64d",&l[i],&r[i]);        if (m.count(l[i]))            m[l[i]]++;        else            m[l[i]]=1;        if (m.count(r[i]+1))            m[r[i]+1]--;        else            m[r[i]+1]=-1;    }    fac[0]=1;    for (i=1;i<=N;i++)        fac[i]=fac[i-1]*i%moder;    for (i=0;i<=N;i++)        inv[i]=power(fac[i],moder-2);    map<long long,long long>::iterator j=m.begin();    for (;j!=m.end();j++)    {        if (j==m.begin())            count+=j->second;        else        {            if (count>=k)                ans=(ans+(j->first-pre)*fac[count]%moder*inv[count-k]%moder*inv[k]%moder)%moder;            count+=j->second;        }        pre=j->first;    }    printf("%I64d",ans);    return 0;}
0 0
原创粉丝点击