2015 北京区域赛现场赛 部分题解

【前言】这场比赛是昨天的训练赛,弱队最终做了4题,好像去年是铜牌滚粗。,太弱啦。现在写一下部分题解。

【A Xiongnu's Land 】 http://7xjob4.com1.z0.glb.clouddn.com/3e76f5f069daf5f6fa79969c155e4e14

【题意】WQ和HQB两个人立了攻,汉武帝要把一块沙漠(这片沙漠是有绿洲存在的)赏给这两个人,这片沙漠是正方形的方式存在的,并且给出了举行右上角的坐标(L,L),而且给出了n个绿洲的坐标,面积,现在汉武帝要用一根线把这片地划分成两个部分,使得左边的绿洲面积要大于等于右边的,并且他们之间的差距尽可能的小。询问这根线的位置,保证正整数。

【解题方法】比较水的题目了,想想就知道要维护一个前缀和的前缀和,这题就做完啦。

【AC 代码】

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
#define LL long long
const int N =2e6;
LL pre[N];
int main()
{
    int T,left,top,w,h,R,n;
    LL sums;
    scanf("%d",&T);
    while(T--){
        memset(pre,0,sizeof(pre));
        scanf("%d%d",&R,&n);
        sums=0;
        for(int i=0;i<n;i++){
            scanf("%d%d%d%d",&left,&top,&w,&h);
            w=min(w,R-left);
            h=min(h,top);
            pre[left+1]+=h;
            pre[left+w+1]-=h;
            //sum[left+w+1]-=1ll*w*h;
            sums+=1ll*w*h;
        }
        for(int i=1;i<=R;i++){
            pre[i]+=pre[i-1];
        }
        for(int i=1;i<=R;i++){
            pre[i]+=pre[i-1];
        }
        int ans=0;
        LL minn=0x3f3f3f3f;
        for(int i=1;i<=R;i++){
            if(pre[i]>=(sums-pre[i])&&pre[i]-(sums-pre[i])<=minn){
                ans=i;
                minn=pre[i]-(sums-pre[i]);
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}

【Today Is a Rainy Day 赛后补题】 https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=5275

【题意】给了2个数字串a和数字串b,并且这些串里最多有1-6这6个数字,现在有两种操作,一种是把串里的某一个数字全部变成另外一个数字,另一种操作是把串里某一个位置上的数字变成另一个数字,问把b串通过这两个操作变成a串最少需要多少步?

【解题方法】只要想到,全部变比一个变肯定来得优,然后我们需处理代价这题就可以做出来了。后面的代价可以直接算嘛,然后维护最小代价就好啦。

【AC 代码】

#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 50005;
const int inf = 0x3f3f3f3f;
int dp[maxn];
int getid1(int *c){
	int ret = 0;
	for(int i=0; i<6; i++){
		ret = ret * 6 + c[i];
	}
	return ret;
}
void getid2(int s,int *c)
{
	for(int i=5; i>=0; i--){
		c[i] = s%6;
		s /= 6;
	}
}

void presolve()
{
	int c[10],t[10];
	for(int i=0; i<6; i++) c[i] = i;
	int s = getid1(c);
	memset(dp,inf,sizeof(dp));
	dp[s] = 0;
	queue<int>que;
	que.push(s);
	while(que.size())
	{
		s = que.front();
		que.pop();
		getid2(s,c);
		for(int i=0; i<6; i++){
			for(int j=0; j<6; j++){
				memcpy(t,c,sizeof(t));
				for(int k=0; k<6; k++) if(t[k]==i) t[k]=j;
				int v = getid1(t);
				if(dp[v]>dp[s]+1){
					dp[v]=dp[s]+1;
					que.push(v);
				}
			}
		}
	}
}
int cnt1[10],cnt2[10][10];
char a[120],b[120];
int main()
{
	presolve();
	while(scanf("%s",a)!=EOF)
	{
		scanf("%s",b);
		int len =strlen(a);
		memset(cnt1,0,sizeof(cnt1));
		memset(cnt2,0,sizeof(cnt2));
		for(int i=0; i<len; i++){
			cnt1[b[i]-'1']++;
			cnt2[b[i]-'1'][a[i]-'1']++;
		}
		int ans = inf;
		int t[10];
		for(int s=0; s<maxn; s++){
			getid2(s,t);
			int now = dp[s];
			for(int i=0; i<6; i++){
				now += cnt1[i] - cnt2[i][t[i]];
			}
			ans = min(ans,now);
		}
		printf("%d\n",ans);
	}
	return 0;
}

【G Mysterious Antiques in Sackler Museum】 https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=5279

【题意】给4个矩形的宽和高,问能否选出3个拼成一个大矩形

【解题方法】简单模拟,不要漏情况就好,这题队友写的,很稳。

【AC 代码】

#include<cstdio>
using namespace std;
struct node
{
    int h,w;
}a[4];
int isok()
{
    for(int i=0;i<4;i++){
        int flag=0;
        for(int j=0;j<4;j++){
            if(j==i) continue;
            if(a[j].h==a[0].h||a[j].w==a[0].h) continue;
            else flag=1;
        }
        if(flag==0) return 1;
        flag=0;
        for(int j=0;j<4;j++){
            if(j==i) continue;
            if(a[j].w==a[0].w||a[j].h==a[0].w) continue;
            else flag=1;
        }
        if(flag==0) return 1;
    }
    return 0;
}
int check()
{
    for(int i=0;i<4;i++){
        for(int j=0;j<4;j++){
            int t1=-1,t2=-1;
            if(i==j) continue;
            for(int k=0;k<4;k++){
                if(k==j||k==i) continue;
                if(t1==-1){
                    t1=k;
                    for(int x=0;x<4;x++){
                        if(x==j||x==t1||x==i) continue;
                        t2=x;
                    }
                    break;
                }
            }
            if(a[t1].h==a[t2].w&&(a[t1].w+a[t2].h==a[j].h||a[t1].w+a[t2].h==a[j].w)) return 1;
            if(a[t1].h==a[t2].h&&(a[t1].w+a[t2].w==a[j].h||a[t1].w+a[t2].w==a[j].w)) return 1;
            if(a[t1].w==a[t2].w&&(a[t1].h+a[t2].h==a[j].h||a[t1].h+a[t2].h==a[j].w)) return 1;
            if(a[t1].w==a[t2].h&&(a[t1].h+a[t2].w==a[j].h||a[t1].h+a[t2].w==a[j].w)) return 1;
        }
    }
    return 0;
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%d%d%d%d%d%d%d%d",&a[0].h,&a[0].w,&a[1].h,&a[1].w,&a[2].h,&a[2].w,&a[3].h,&a[3].w);
        if(isok()) printf("Yes\n");
        else if(check()) printf("Yes\n");
        else printf("No\n");
    }
    return 0;
}


【I Snake Carpet 】https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=5281

【题意】给一个数n,然后现在对于1-n的每一个数i,你都可以用这i个相同的数字i构成一条长度为i的蛇,要满足一个条件,就是>2的偶数的转弯必须是偶数,奇数必须是奇数。

【解题方法】队友在纸上画了一下,感觉是蛇形填数,乱扒了几组样例,感觉还是挺妥的,就开始敲了,不过这题我们debug了很久,中间下标什么很烦,orz。

【AC 代码】

#include <cstdio>
#include <algorithm>
using namespace std;
struct node
{
    int x,y;
};
node ans[1000][1000];
int numm[1000];
void f(int n,int x,int y)
{
    if(n<=0) return ;
    if(n==1){
        printf("%d %d\n",x,y);
        return ;
    }
    if(n%2==0){
        f(n-1,x,y+2);
        int i=x,j=y,k,flag=0;
        for(k=0;k<n/2;k++,i--){
            if(flag==0) printf("%d %d",i,j),flag=1;
            else printf(" %d %d",i,j);
        }
        i++;
        for(k=0,j++;k<n/2;k++,i++){
            if(flag==0) printf("%d %d",i,j),flag=1;
            else printf(" %d %d",i,j);
        }
        printf("\n");
    }
    else if(n>=3){
        f(n-3,x,y+2);
        int i=x,j=y,k,cnt=0,num;
        num=0;
        for(k=0;k<(n+1)/2;k++,i--) ans[cnt][num++]=(node){i,j};
        i++;
        for(k=0,j++;k<n/2;k++,j++) ans[cnt][num++]=(node){i,j};
        numm[cnt++]=num;
        j--;
        num=0;
        for(k=0,j++;k<(n-1)/2;k++,j++) ans[cnt][num++]=(node){i,j};
        j--;
        for(i++,k=0;k<(n-1)/2;k++,j--) ans[cnt][num++]=(node){i,j};
        numm[cnt++]=num;
        j++;
        num=0;
        for(k=0,j--;k<(n-2)/2+1;k++,j--) ans[cnt][num++]=(node){i,j};
        j++;
        for(k=0,i++;k<(n-2)/2;k++,i++) ans[cnt][num++]=(node){i,j};
        numm[cnt++]=num;
        for(int i=cnt-1;i>=0;i--){
            for(int j=0;j<numm[i];j++){
                if(j==0) printf("%d %d",ans[i][j].x,ans[i][j].y);
                else printf(" %d %d",ans[i][j].x,ans[i][j].y);
            }
            printf("\n");
        }
    }
}
int main()
{
    int n;
    while(~scanf("%d",&n)){
        if(n%2==0) printf("%d %d\n",n/2,n+1);
        else printf("%d %d\n",(n+1)/2,n);
        if(n%2==0) f(n,n/2,1);
        else f(n,(n+1)/2,1);
    }
    return 0;
}

J - Osu! Master】 https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=5282

【题意】不是太懂,我直接看样例,猜了个结论秒过,我的结论就是连续上升的数字或者s的和。

【解题方法】如上。

【AC 代码】

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
int n;
int main()
{
    while(scanf("%d",&n)!=EOF)
    {
        int x;
        char op[3];
        int ans=0;
        int last=-1;
        for(int i=0; i<n; i++){
            scanf("%s",op);
            if(op[0]=='S'){
                ans++;
                last=-1;
            }else{
                scanf("%d",&x);
                if(x>last&&last!=-1){
                    last=x;
                    continue;
                }else{
                    ans++;
                    last=x;
                }
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值