2019dut周赛第一周

A题

题解:

B题

题解:

C题

题意:

题解:

观察到n只有3 特判三种情况输出即可

D题

题解:

找题意遍历数组即可,如果wa是因为异或(^)运算符优先级比不等于(!=)低  给等式加上括号即可

E题

题解:

我们可以通过求每个耕地与离它最近的洒水器的距离的最小值,然后对所有耕地的最大值就可以得到k

先将洒水器和耕地的位置从小到大排序,然后从小到大求每个耕地在哪两个洒水器之间(即求每个耕地右边第一个洒水器的位置),这两个洒水器和耕地的距离的最小值就是耕地和离它最近的洒水器的距离。又因为耕地坐标从小到大,所以每个耕地右边第一个洒水器的位置也一定是从小到大的。具体看代码

#include<bits/stdc++.h>
using namespace std;
const int N = 100010;
int n,m;
int a[N];//耕地坐标 
int b[N];//洒水器坐标 
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) {
        scanf("%d",&a[i]);
    }
    for(int i=1;i<=m;i++) {
        scanf("%d",&b[i]);
    }
    sort(a+1,a+1+n);
    sort(b+1,b+1+m);
    b[0] = -2e9; b[m+1] = 2e9;//添加边界条件 
    int ans = 1;
    int now = 1;//当前耕地右边第一个洒水器的位置 
    for(int i=1;i<=n;i++) {
    	//如果这个洒水器在耕地左边,那考虑更往右的一个洒水器 
        while(b[now]<a[i]){
            now++;
        }
        //dis为左边第一个洒水器和右边第一个洒水器和耕地距离的最小值 
        int dis=min(abs(a[i]-b[now]),abs(a[i]-b[now-1]));
        ans = max(ans,dis);
    }
    printf("%d\n",ans);
    return 0;
}

F题

题解

举报吕大佬!吕大佬出的原题

G题

题解

显然染k次 最多能染成2*k-1段不同的颜色,那就直接动态规划就好了(如果还没学过动态规划,可以去百度一下 先看看入门题)

#include<bits/stdc++.h>
 
using namespace std;
 //dp[i][j][k]表示当前是第i种颜色,之前一共染出j段不同的颜色,且当前染到第k面墙的最大值 
int dp[2][120][100100];
int a[100100];
int main(){
    int n;
    int k;
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
    }
     
    if(a[1]==1) dp[1][0][1]=1;
    else dp[0][0][1]=1;
    for(int i=2;i<=n;i++){
        int now=0;
        dp[now][0][i]=dp[now][0][i-1]+(now==a[i]);
        now=1;
        dp[now][0][i]=dp[now][0][i-1]+(now==a[i]);
        for(int j=1;j<=2*(k-1);j++){
            int now=0;
            //考虑上一块染得是蓝色,不换色直接再染一格 
            dp[now][j][i]=dp[now][j][i-1]+(now==a[i]);
            //考虑上一块染得是蓝色,之前染成i-1段,这一块染成红色变成i段 
            dp[now][j][i]=max(dp[now][j][i],dp[now^1][j-1][i-1]+((now^1)==a[i]));
            now =1;
            //考虑上一块染得是红色,不换色直接再染一格 
            dp[now][j][i]=dp[now][j][i-1]+(now==a[i]);
            //考虑上一块染得是红色,之前染成i-1段,这一块染成烂色变成i段
            dp[now][j][i]=max(dp[now][j][i],dp[now^1][j-1][i-1]+((now^1)==a[i]));
        }
    }
    int ans=0;
    for(int i=0;i<=2*(k-1);i++){
        ans=max(ans,dp[0][i][n]);
        ans=max(ans,dp[1][i][n]);
    }
    printf("%d\n",ans);
} 

H题

题解

四种钱币价值为1,5,12,60 ,可以看成有n个数每个数可以是0,4,11,59,问有多少种不同的和

假设只有0,4,11三个数,假如n<11那取i个4,j个11,只要i+j<n那和就是不同的。如果n>=11,那么取超过11个4就是没有意义的。

因为可以把11个4换成4个11,此时每能多取一个数,就能多取11个不同的数。

有0,4,11,59 四个数时,当n足够大,也会变成和上面类似的情况,n没增加1,最多有59个新的不同的数

如何找到这个n呢?写个枚举即可

int maze[10100];
int ans[100]={0,4,10,20,35,56,83,116,155,200,251,306,364,424,484,543,602,661,720,779,838};
int gett(int n){
    int ans=0;
    for(int i=0;i<=n;i++){
        for(int j=0;j+i<=n;j++){
            for(int k=0;k+i+j<=n;k++){
                maze[i*4+j*11+k*59]=1;
            }
        }
    }
    for(int i=0;i<10000;i++) {
        ans+=maze[i];
        maze[i]=0;
    }
    return ans;
}

 

J题

题解

首先,切比雪夫距离下很容易想到二维偏序加扫描线的做法,但是复杂度是O(n*logn*logn)的,1s时限显然不能通过

那么考虑将其转化成曼哈顿距离,然后就变成了两组点,求第一组中每个点与第二组中曼哈顿距离的最小值

这个有一篇论文可供参考:论一类平面点对曼哈顿距离问题_百度文库

简单点说就是分开求每个点左上右上左下右下的点离它最近的距离,这样就可以拆掉曼哈顿距离中的绝对值,用树状数组或者线段树维护即可

代码

#include<bits/stdc++.h>
#define f first
#define s second
#define pb push_back
using namespace std;
int const maxn=1e5+5;
int const inf=0x3f3f3f3f;
typedef pair<int,int>P;
vector<int>u;
int res[maxn],dat[maxn<<3];
struct node{
    P a;int ls,id;
}p[maxn<<1];
bool cmp1(node x,node y){
    if(x.a.s==y.a.s) return x.a.f<y.a.f;
    return x.a.s<y.a.s;
}
bool cmp2(node x,node y){
    if(x.a.s==y.a.s) return x.a.f<y.a.f;
    return x.a.s>y.a.s;
}
void inline pushup(int p){
    dat[p]=max(dat[p<<1],dat[p<<1|1]);
}
int ask(int p,int l,int r,int ql,int qr){
    if(ql<=l&&r<=qr) return dat[p];
    int mid=l+r>>1,res=-inf;
    if(ql<=mid) res=max(res,ask(p<<1,l,mid,ql,qr));
    if(qr>mid) res=max(res,ask(p<<1|1,mid+1,r,ql,qr));
    return res;
}
void update(int p,int l,int r,int x,int w){
    if(l==r) {
        dat[p]=max(dat[p],w);
        return ;
    }
    int mid=l+r>>1;
    if(x<=mid) update(p<<1,l,mid,x,w);
    else update(p<<1|1,mid+1,r,x,w);
    pushup(p);
}
void build(int p,int l,int r){
    dat[p]=-inf;
    if(l==r) return ;
    int mid=l+r>>1;
    build(p<<1,l,mid);
    build(p<<1|1,mid+1,r);
}
int main(){
    int n,m,k;
    scanf("%d%d",&n,&m);
    memset(res,0x3f,sizeof(res));
    k=n+m;
    for(int i=1;i<=k;i++){
        int xx,yy;
        scanf("%d%d",&xx,&yy);
      //  scanf("%d%d",&p[i].a.f,&p[i].a.s);
        p[i].a.f=xx+yy;
        p[i].a.s=xx-yy;
        u.pb(p[i].a.f);
        if(i<=n) p[i].id=i;
        else p[i].id=0;
    }
    sort(u.begin(),u.end());
    u.erase(unique(u.begin(),u.end()),u.end());
    for(int i=1;i<=k;i++) p[i].ls=lower_bound(u.begin(),u.end(),p[i].a.f)-u.begin()+1;
    int rt=u.size();
    sort(p+1,p+k+1,cmp1);
    build(1,1,rt);
    for(int i=1;i<=k;i++) if(p[i].id) res[p[i].id]=min(res[p[i].id],p[i].a.f+p[i].a.s-ask(1,1,rt,1,p[i].ls));
    else update(1,1,rt,p[i].ls,p[i].a.f+p[i].a.s);
    build(1,1,rt);
    for(int i=k;i>=1;i--) if(p[i].id) res[p[i].id]=min(res[p[i].id],-ask(1,1,rt,p[i].ls,rt)-p[i].a.f-p[i].a.s);
    else update(1,1,rt,p[i].ls,-p[i].a.f-p[i].a.s);
    sort(p+1,p+k+1,cmp2);
    build(1,1,rt);
    for(int i=1;i<=k;i++) if(p[i].id) res[p[i].id]=min(res[p[i].id],p[i].a.f-p[i].a.s-ask(1,1,rt,1,p[i].ls));
    else update(1,1,rt,p[i].ls,p[i].a.f-p[i].a.s);
    build(1,1,rt);
    for(int i=k;i>=1;i--) if(p[i].id) res[p[i].id]=min(res[p[i].id],-ask(1,1,rt,p[i].ls,rt)-p[i].a.f+p[i].a.s);
    else update(1,1,rt,p[i].ls,-p[i].a.f+p[i].a.s);
    int ans=0;
    for(int i=1;i<=n;i++) ans=max(ans,res[i]);
    printf("%d\n",ans/2);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值