Codeforces Round #587 C E1 F题解

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

C. White Sheet

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

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

#include
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

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
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
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;
}

 

你可能感兴趣的:(cf补提)