Codeforces Round #587 C E1 F题解

本文解析了CodeForces平台上的三道题目,包括矩形覆盖判断、数字序列查询及Wi-Fi网络覆盖问题,通过详细代码和算法思路展示了如何解决这些挑战。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

比赛链接:https://codeforces.com/contest/1216

C. White Sheet

题意:给出三个长方形的横纵坐标 (左下角和右上角),问后两个长方形是否将第一个完全覆盖;

思路:将坐标离散化,用二维数组模拟染色判断;(代码写的很丑。。)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const int N=2e5+10;
 
struct node
{
    int x,y,k,id;
} q[10];
 
bool cmp1(node x,node y)
{
    return x.x<y.x;
}
 
bool cmp2(node a,node b)
{
    return a.y<b.y;
}
 
struct pos
{
    int x,y,k;
} p[10];
 
int mp[10][10];
 
int main()
{
    for(int i=0; i<6; i++)
    {
        scanf("%d %d",&q[i].x,&q[i].y);
        q[i].id=i;
        if(i==0||i==1)
            q[i].k=1;
        if(i==2||i==3)
            q[i].k=2;
        if(i==4||i==5)
            q[i].k=3;
    }
    sort(q,q+6,cmp1);
    int top=1;
    p[q[0].id].x=1;
    p[q[0].id].k=q[0].k;
    for(int i=1; i<6; i++)
    {
        if(q[i].x!=q[i-1].x)
            top++;
        p[q[i].id].x=top;
        p[q[i].id].k=q[i].k;
    }
    sort(q,q+6,cmp2);
    top=1;
    p[q[0].id].y=1;
    for(int i=1; i<6; i++)
    {
        if(q[i].y!=q[i-1].y)
            top++;
        p[q[i].id].y=top;
    }
    for(int i=p[0].y; i<p[1].y; i++)
        for(int j=p[0].x; j<p[1].x; j++)
            mp[i][j]=1;
    for(int i=p[2].y; i<p[3].y; i++)
        for(int j=p[2].x; j<p[3].x; j++)
            mp[i][j]=2;
    for(int i=p[4].y; i<p[5].y; i++)
        for(int j=p[4].x; j<p[5].x; j++)
            mp[i][j]=2;
    for(int i=1;i<=6;i++)
    {
        for(int j=1;j<=6;j++)
        {
            if(mp[i][j]==1)
            {
                printf("YES\n");
                return 0;
            }
        }
    }
    printf("NO\n");
    return 0;
}

E1 - Numerical Sequence (easy version)

题意:规定一个序列,q此询问,每次询问序列第k个的数值;

规定的序列是:112123123412345……;

思路:记录每个数字构成串的长度  例如 a[10]=11  (12345678910,长度为11),记录每个数字构成串的长度的前缀和,例如
sum[5]=a[1]+a[2]+a[3]+a[4]+a[5]=15;然后二分再二分,第一个二分找是第几个数字构成的串,第二次二分是具体数字;

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll inf=0x3f3f3f3f3f3f3f3f;
const int N=8e4+10;

ll sum[N],a[N],b[N];

int main()
{
    for(ll i=1;i<=30000;i++)
    {
        if(i>=10000) a[i]=a[i-1]+5;
        else if(i>=1000) a[i]=a[i-1]+4;
        else if(i>=100) a[i]=a[i-1]+3;
        else if(i>=10) a[i]=a[i-1]+2;
        else a[i]=a[i-1]+1;
        sum[i]=sum[i-1]+a[i];
    }
    printf("%lld\n",sum[30000]);
    ll q,k;
    scanf("%lld",&q);
    for(ll i=1;i<=q;i++)
    {
        scanf("%lld",&k);
        ll tmp=lower_bound(sum+1,sum+30000,k)-sum,e=0;
        k=k-sum[tmp-1];
        ll t=lower_bound(a+1,a+30000,k)-a;
        if(a[t-1]==k)
        {
            k=k-a[t-1]+1;
            t--;
        }
        else k=k-a[t-1];
        while(t)
        {
            ll x=t%10;
            t/=10;
            b[++e]=x;
        }
        printf("%lld\n",b[e-k+1]);
    }
    return 0;
}

F. Wi-Fi

题意:有n间宿舍编号1~n,要给没间宿舍联网,可以直接联网,有的宿舍安放了路由器,路由器可以覆盖(i-k,i+k)宿舍,别的宿舍安置的路由器联网,第 i 个宿舍直接联网需要花费 i 元,被路由器覆盖不花钱,路由器也需要联网才能使用,第 i 个房间的路由器联网花费需要 i 元,问网覆盖全部宿舍的最少花费;

/*
思路:dp[i][0]表示前i间宿舍通过直接联网需要的最小花费;
      dp[i][1]表示如果第i间宿舍有路由器,并且路由器联网的前i间宿舍的最小花费;
      没有路由器的宿舍,可以通过 i-k~i-1 间宿舍的路由器联网;
      有路由器的宿舍,可以通过线段树找 i-k-1~i-1之间的最小花费来更新;
*/
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll inf=0x3f3f3f3f3f3f3f3f;
const int N=2e5+10;
 
char str[N];
ll a[2][N*4],dp[N][2];
 
void build(ll *tree,ll a,ll b,ll r)
{
    tree[r]=inf;
    if(a==b) return;
    ll mid=(a+b)/2;
    build(tree,a,mid,r<<1);
    build(tree,mid+1,b,r<<1|1);
    tree[r]=min(tree[r<<1],tree[r<<1|1]);
}
 
void update(ll *tree,ll a,ll b,ll r,ll val,ll qa)
{
    if(a==b)
    {
        tree[r]=val;
        return;
    }
    ll mid=(a+b)/2;
    if(qa<=mid) update(tree,a,mid,r<<1,val,qa);
    else update(tree,mid+1,b,r<<1|1,val,qa);
    tree[r]=min(tree[r<<1],tree[r<<1|1]);
}
 
ll query(ll *tree,ll a,ll b,ll r,ll qa,ll qb)
{
    if(a>=qa&&b<=qb) return tree[r];
    ll mid=(a+b)/2,res=inf;
    if(qa<=mid) res=min(res,query(tree,a,mid,r<<1,qa,qb));
    if(qb>mid) res=min(res,query(tree,mid+1,b,r<<1|1,qa,qb));
    return res;
}
 
int main()
{
    ll n,k;
    scanf("%lld %lld",&n,&k);
    scanf("%s",str+1);
    build(a[0],1,n,1);
    build(a[1],1,n,1);
    dp[n][1]=inf;
    dp[0][0]=0;
    for(ll i=1;i<=n;i++)
    {
        if(i>1) dp[i][0]=min(i+dp[i-1][0],query(a[1],1,n,1,i-k,i-1));
        else dp[i][0]=i;
        update(a[0],1,n,1,dp[i][0],i);
        if(str[i]=='1')
        {
            if(i-k<=1) dp[i][1]=i;
            else if(i>1) dp[i][1]=min(query(a[0],1,n,1,i-k-1,i-1),query(a[1],1,n,1,i-k-1,i-1))+i;
            update(a[1],1,n,1,dp[i][1],i);
        }
    }
    printf("%lld\n",min(dp[n][1],dp[n][0]));
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值