2015 Multi-University Training Contest 2

官方题解:2015 Multi-University Training Contest 2 solutions BY 学军中学


1002 Buildings

HDU 5301:http://acm.hdu.edu.cn/showproblem.php?pid=5301
题意:有一个n*m的大矩阵,其中有一个1*1的坏格,求用若干个小矩阵去覆盖大矩阵,坏格不能被覆盖。问小矩阵中面积最大的面积最小是多少。给出n,m以及坏格的位置x,y


如果没有坏格,那么答案应该是\(ans'=(min(m,n)+1)/2\)

有了坏格就要考虑坏格周围的4个格子是否能被覆盖到


交换\(n,m\)使\(n \leqslant m\),并把坏格装换到矩阵左上角

那么需要被覆盖的就是坏格下方的那个格子,只要它能被覆盖,那么其他4个格子也一定能被覆盖。

同时要注意ans的长度不会超过\((m+1)/2\)。那么\(ans=min((m+1)/2,max(ans’,min(n-x,y)))\)


特殊情况:当大矩阵为正方形,且坏格位于方形中心时,\(ans=ans'-1\)


#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<cstring>
#include<queue>
using namespace std;
#define MAX(a,b) ((a>b)?(a):(b))
#define MIN(a,b) ((a<b)?(a):(b))
#define LL __int64
#define N 100005
#define INF 1<<30


int main() {

    int n,m,x,y;
    while(scanf("%d%d%d%d",&n,&m,&x,&y)!=EOF) {
        if(n>m) {
            swap(n,m);
            swap(x,y);
        }
        int ans=(min(n,m)+1)/2;
        x=min(x,n-x+1);
        y=min(y,m-y+1);
        if(n==m&&(n&1)&&x==y&&x==(n+1)/2)
            ans--;
        else {
            ans=min((m+1)/2,max(ans,min(n-x,y)));
        }
        printf("%d\n",ans);
    }
    return 0;
}


1004 Delicious Apples

HDU 5303:http://acm.hdu.edu.cn/showproblem.php?pid=5303

题意:在一个长为L的环形路上有n个苹果数,坐标为0的位置为起点。分别给出了苹果树距离起点的长度\(x_i\)(顺时针)和苹果数量\(a_i\),现在有一个最多能装\(k\)个苹果的篮子,从起点出发,往返摘取苹果,问最短的行走距离。

\(1\leqslant n ,k\leqslant 10^5,1\leqslant L\leqslant 10^9\)


如果将环路从\(\frac{L}{2}\)处断开,那么便可以左右分别贪心求出最小的\(ans\)

但因为是环形,就要考虑一种特殊情况,可能需要绕整个环一周。因为左右两边贪心完后可能剩下小于\(k\)个的苹果(如果剩下大于\(k\)个,那么大于那部分走半边就可以摘取),对于这种情况特殊处理,然后取最小值。

PS:注意用__int64


#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<cstring>
#include<queue>
#include<vector>
using namespace std;
#define MAX(a,b) ((a>b)?(a):(b))
#define MIN(a,b) ((a<b)?(a):(b))
#define LL __int64
#define N 100005
#define INF 1<<30

LL l[N],r[N];
int l_cnt,r_cnt;
int main() {
    //freopen("C:\\Users\\F\\Desktop\\in.txt", "r", stdin);
    //freopen("C:\\Users\\F\\Desktop\\out.txt", "w", stdout);

    int t;
    int n,k,L;
    int x,a;
    LL ans;
    scanf("%d",&t);
    while(t--) {
        ans=0;
        memset(l,0,sizeof(l));
        memset(r,0,sizeof(r));
        l_cnt=1;
        r_cnt=1;
        scanf("%d%d%d",&L,&n,&k);
        for(int i=1; i<=n; ++i) {
            scanf("%d%d",&x,&a);
            while(a--) {
                if(x*2<L)
                    l[l_cnt++]=x;
                else
                    r[r_cnt++]=L-x;
            }
        }
        l_cnt--,r_cnt--;
        sort(l+1,l+l_cnt+1);
        sort(r+1,r+r_cnt+1);
        for(int i=1; i<=l_cnt; ++i) {
            if(i>k) {
                l[i]+=l[i-k];
            }
        }
        for(int i=1; i<=r_cnt; ++i) {
            if(i>k) {
                r[i]+=r[i-k];
            }
        }
        ans=(l[l_cnt]+r[r_cnt])*2;

        for(int i=0; i<=k; ++i) {
            ans=min(ans,L+(l[l_cnt-i]+r[max(0,r_cnt-(k-i))])*2);
        }
        printf("%I64d\n",ans);
    }

    return 0;
}



1006 Friends

HDU 5305:http://acm.hdu.edu.cn/showproblem.php?pid=5305

题意:n个人m对朋友,对于每对朋友可以选择成为线上朋友或者线下朋友,但要求每人的线上朋友数等于线下朋友数,问有多少种选择方法

\(1\leqslant n \leqslant 8\)


当n=8时,\(\frac{8\times7}{2}=28\)条边,如果直接暴力枚举的话需要枚举\(2^{28}\approx10^8\)次,明显会TLE

考虑剪枝,如果枚举的时候考虑当前边的两点,不让点的某一种朋友数超过点度数的\(\frac{1}{2}\),便会节省掉很大一部分时间。


#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<cstring>
#include<queue>
using namespace std;
#define MAX(a,b) ((a>b)?(a):(b))
#define MIN(a,b) ((a<b)?(a):(b))
#define LL __int64
#define N 100005
#define INF 1<<30

int n,m;
int ans;
int on[10],off[10];
int vis[10];
struct Edge {
    int a,b;
} e[110];

void dfs(int k) {
    if(k==m) {
        for(int i=1; i<=n; ++i)
            if(on[i]!=off[i])return;
        ans++;
        return ;
    }
    int a=e[k].a,b=e[k].b;
    if(on[a]<vis[a]/2&&on[b]<vis[b]/2) {
        on[a]++,on[b]++;
        dfs(k+1);
        on[a]--,on[b]--;
    }
    if(off[a]<vis[a]/2&&off[b]<vis[b]/2) {
        off[a]++,off[b]++;
        dfs(k+1);
        off[a]--,off[b]--;
    }
}

int main() {
    int T;
    scanf("%d",&T);
    while(T--) {
        scanf("%d%d",&n,&m);
        ans=0;
        int flag=0;
        memset(vis,0,sizeof(vis));
        memset(on,0,sizeof(on));
        memset(off,0,sizeof(off));
        for(int i=0; i<m; ++i) {
            scanf("%d%d",&e[i].a,&e[i].b);
            vis[e[i].a]++;
            vis[e[i].b]++;
        }
        for(int i=1; i<=n; ++i) {
            if(vis[i]&1)flag=1;
        }
        if(flag) {
            printf("0\n");
            continue;
        }
        dfs(0);
        printf("%d\n",ans);
    }
    return 0;
}


1007 Gorgeous Sequence

HDU 5306:http://acm.hdu.edu.cn/showproblem.php?pid=5306
题意:一个长度为n的序列a,定义三种操作:

0 x y t: 对于\(x\leqslant i \leqslant y\),令\(a_i=min(a_i,t)\)

1 x y: 输出区间\([x,y]\)内的最大值

2 x y: 输出区间\([x,y]\)内的数的和


线段树区间合并

用一个cover数组去记录lazy标记影响了多少个数


用平时的输入外挂还过不了。。贴一个标程的输入外挂

/************Read**********/
char *ch, *ch1, buf[40*1024000+5], buf1[40*1024000+5];

void read(int &x)
{
    for (++ch; *ch <= 32; ++ch);
    for (x = 0; '0' <= *ch; ch++)    x = x * 10 + *ch - '0';
}

/**************************/

int main(){

    ch = buf - 1;
    ch1 = buf1 - 1;
    fread(buf, 1, 1000 * 35 * 1024, stdin);

    int x;
    read(x);

    return 0;
}

AC代码

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<cstring>
#include<queue>
#include<vector>
#include<string>
using namespace std;
#define MAX(a,b) ((a>b)?(a):(b))
#define MIN(a,b) ((a<b)?(a):(b))
#define LL __int64
#define N 1000005
#define INF 1<<30
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1


/************Read**********/
char *ch, *ch1, buf[40*1024000+5], buf1[40*1024000+5];

void read(int &x)
{
    for (++ch; *ch <= 32; ++ch);
    for (x = 0; '0' <= *ch; ch++)    x = x * 10 + *ch - '0';
}

/**************************/

LL sum[N<<2];
int mmax[N<<2];
int tag[N<<2];
int cover[N<<2];

void pushup(int rt){
    sum[rt]=sum[rt<<1]+sum[rt<<1|1];
    mmax[rt]=max(mmax[rt<<1],mmax[rt<<1|1]);
    cover[rt]=cover[rt<<1]+cover[rt<<1|1];
}

void mark(int t,int l,int r,int rt){
    if(tag[rt]!=0&&tag[rt]<=t)return;
    tag[rt]=t;
    if(cover[rt]!=r-l+1){
        mmax[rt]=t;
        sum[rt]+=(LL)(r-l+1-cover[rt])*t;
        cover[rt]=r-l+1;
    }
}

void pushdown(int l,int r,int rt){
    if(tag[rt]){
        int m=(l+r)>>1;
        mark(tag[rt],lson);
        mark(tag[rt],rson);
    }
}

void build(int l,int r,int rt){
    tag[rt]=0;
    if(l==r){
        read(tag[rt]);
        sum[rt]=mmax[rt]=tag[rt];
        cover[rt]=1;
        return;
    }
    int m=(l+r)>>1;
    build(lson);
    build(rson);
    pushup(rt);
}



void clear(int t,int l,int r,int rt){
    if(mmax[rt]<t)return;
    if(tag[rt]>=t)
        tag[rt]=0;

    if(l==r){
        sum[rt]=mmax[rt]=tag[rt];
        cover[rt]=(tag[rt]!=0);
        return;
    }

    int m=(l+r)>>1;
    pushdown(l,r,rt);
    clear(t,lson);
    clear(t,rson);
    pushup(rt);
}

void update(int L,int R,int t,int l,int r,int rt){
    if(mmax[rt]<=t)return;
    if(L<=l&&r<=R){
        clear(t,l,r,rt);
        if(l==r){
            sum[rt]=mmax[rt]=tag[rt]=t;
            cover[rt]=1;
        }else{
            pushup(rt);
        }
        mark(t,l,r,rt);
        return;
    }
    int m=(l+r)>>1;
    pushdown(l,r,rt);
    if(L<=m)update(L,R,t,lson);
    if(R>m)update(L,R,t,rson);
    pushup(rt);
}

LL query(int L,int R,int op,int l,int r,int rt){
    if(L<=l&&r<=R){
        switch(op){
            case 1:return mmax[rt];break;
            case 2:return sum[rt];break;
        }
    }
    int m=(l+r)>>1;
    LL ret=0;
    pushdown(l,r,rt);
    if(L<=m){
        switch(op){
            case 1:ret=max(ret,query(L,R,op,lson));break;
            case 2:ret+=query(L,R,op,lson);break;
        }
    }
    if(R>m){
         switch(op){
            case 1:ret=max(ret,query(L,R,op,rson));break;
            case 2:ret+=query(L,R,op,rson);break;
        }
    }
    pushup(rt);
    return ret;
}

void show(int l,int r,int rt){
    if(l==r){
        printf("%I64d",sum[rt]);
        return ;
    }
    int m=(l+r)>>1;
    pushdown(l,r,rt);
    show(lson);
    show(rson);
    pushup(rt);
}



int main(){

    ch = buf - 1;
    ch1 = buf1 - 1;
    fread(buf, 1, 1000 * 35 * 1024, stdin);
    int T;
    int n,m;
    int op,x,y,t;
    read(T);
    while(T--){
        read(n);
        read(m);
        build(1,n,1);
        while(m--){
            read(op);
            read(x);
            read(y);
            if(op==0){
                read(t);
                update(x,y,t,1,n,1);
            }else if(op==1){
                printf("%d\n",query(x,y,1,1,n,1));
            }else{
                printf("%I64d\n",query(x,y,2,1,n,1));
            }
        }
    }
    return 0;
}



1009 I Wanna Become A 24-Point Master

HDU 5308:http://acm.hdu.edu.cn/showproblem.php?pid=5308
题意:给n个整数n,用“+”,“-”,“*”,“/”,括号凑24点。

\(1\leqslant n \leqslant 10^5\)


对于\(n<15\)时可以打表:

\(n\leqslant 3,\)无解

\(n=4,4*4+4+4=24\)

\(n=5,(5-\frac{\frac{5}{5}}{5})\times 5=24\)

\(n=6,6+6+6+6=24\)

\(n=7,\frac{7\times7-\frac{7}{7}}{7+7}\times7=24\)

\(n=8,8+8+8=24\)

\(n=9,9+9+9-\frac{9}{9}-\frac{9}{9}-\frac{9}{9}=24\)

\(n=10,10+10+\frac{10+10}{10}+\frac{10+10}{10}=24\)

\(n=11,11+11+\frac{11+11}{11}=24\)

\(n=12,12+12=24\)

\(n=13,13+13-\frac{13+13}{13}=24\)

\(n=14,14+14-\frac{14+14}{14}-\frac{14+14}{14}=24\)

对于\(n\geqslant 15\):

\(\frac{n+n}{n}*\frac{n+n}{n}*\frac{n+n}{n}*\frac{n+n+n}{n}=24\)

对于多余的n可以用两个n相减得0,在把多余的n乘掉。

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<cstring>
#include<queue>
using namespace std;
#define MAX(a,b) ((a>b)?(a):(b))
#define MIN(a,b) ((a<b)?(a):(b))
#define LL __int64
#define N 100005
#define INF 1<<30


int main() {
    //freopen("C:\\Users\\F\\Desktop\\in.txt", "r", stdin);
    //freopen("C:\\Users\\F\\Desktop\\out.txt", "w", stdout);
    int n;
    while(scanf("%d",&n)!=EOF) {
        if(n<=3)
            printf("-1\n");
        else {
            if(n==4) {
                printf("1 * 2\n");
                printf("5 + 3\n");
                printf("6 + 4\n");
            } else if(n==5) {
                printf("1 / 2\n");//6
                printf("6 / 3\n");//7
                printf("4 - 7\n");//8
                printf("5 * 8\n");//9
            } else if(n==6) {
                printf("1 + 2\n");
                printf("7 + 3\n");
                printf("8 + 4\n");
                printf("9 + 5\n");
                printf("10 - 6\n");
            } else if(n==7) {
                printf("1 / 2\n");//8
                printf("3 * 4\n");//9
                printf("9 - 8\n");//10
                printf("5 + 6\n");//11
                printf("10 / 11\n");//12
                printf("12 * 7\n");//13
            } else if(n==8) {
                printf("1 + 2\n");//9
                printf("9 + 3\n");//10
                printf("4 - 5\n");//11
                printf("11 * 6\n");//12
                printf("12 * 7\n");//13
                printf("13 * 8\n");//14
                printf("10 + 14\n");//15
            } else if(n==9) {
                printf("1 + 2\n");//10
                printf("10 + 3\n");//11
                printf("4 / 5\n");//12
                printf("6 / 7\n");//13
                printf("8 / 9\n");//14
                printf("11 - 12\n");//15
                printf("15 - 13\n");//16
                printf("16 - 14\n");//17
            } else if(n==10) {
                printf("1 + 2\n");//11
                printf("3 + 4\n");//12
                printf("12 / 5\n");//13
                printf("11 + 13\n");//14
                printf("6 + 7\n");//15
                printf("15 / 8\n");//16
                printf("14 + 16\n");//17
                printf("17 + 9\n");//18
                printf("18 - 10\n");//19
            } else if(n==11) {
                printf("1 + 2\n");//12
                printf("3 + 4\n");//13
                printf("13 / 5\n");//14
                printf("12 + 14\n");//15
                printf("6 - 7\n");//16
                printf("16 * 8\n");//17
                printf("17 * 9\n");//18
                printf("18 * 10\n");//19
                printf("19 * 11\n");//20
                printf("20 + 15\n");//20
            } else if(n==12) {
                printf("1 + 2\n");//13
                printf("3 - 4\n");//14
                printf("14 * 5\n");//15
                printf("15 * 6\n");//16
                printf("16 * 7\n");//17
                printf("17 * 8\n");//18
                printf("18 * 9\n");//19
                printf("19 * 10\n");//20
                printf("20 * 11\n");//21
                printf("21 * 12\n");//22
                printf("22 + 13\n");//23
            } else if(n==13) {
                printf("1 + 2\n");//14
                printf("3 + 4\n");//15
                printf("15 / 5\n");//16
                printf("14 - 16\n");//17
                printf("6 - 7\n");//18
                printf("18 * 8\n");//19
                printf("19 * 9\n");//20
                printf("20 * 10\n");//21
                printf("21 * 11\n");//22
                printf("22 * 12\n");//23
                printf("23 * 13\n");//24
                printf("24 + 17\n");//25
            } else if(n==14) {
                printf("1 + 2\n");//15
                printf("3 + 4\n");//16
                printf("16 / 5\n");//17
                printf("15 - 17\n");//18
                printf("6 + 7\n");//19
                printf("19 / 8\n");//20
                printf("18 - 20\n");//21
                printf("9 - 10\n");//22
                printf("22 * 11\n");//23
                printf("23 * 12\n");//24
                printf("24 * 13\n");//25
                printf("25 * 14\n");//26
                printf("26 + 21\n");//27
            } else {
                printf("1 + 2\n");//1
                printf("%d / 3\n",n+1);//2
                printf("4 + 5\n");//3
                printf("%d / 6\n",n+3);//4
                printf("%d * %d\n",n+2,n+4);//5
                printf("7 + 8\n");//6
                printf("%d / 9\n",n+6);//7
                printf("%d * %d\n",n+5,n+7);//8
                printf("10 + 11\n");//9
                printf("%d + 12\n",n+9);//10
                printf("%d / 13\n",n+10);//11
                printf("%d * %d\n",n+8,n+11);//12
                printf("14 - 15\n");//13
                int lnow=n+13;
                int now=16;
                while(now<=n) {
                    printf("%d * %d\n",lnow++,now++);
                }
                printf("%d + %d\n",lnow,n+12);
            }
        }
    }
    return 0;
}


(待续。。。)


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值