Codeforces Round #361 (Div. 2)题解

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

  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 200010
using 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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值