NEFU要崛起——第2场

比赛地址:http://acm.hust.edu.cn:8080/judge/contest/view.action?cid=17674#overview

第一题:这题给你一个棋盘的两个格子,问国王从第一个格子到第二个格子的最短路

分析:签到题,仔细讨论情况基本没问题,贴下我代码:

#include<cmath>
#include<cstdio>
#include<iostream>
using namespace std;
char a[9],b[9];
int main()
{
	while(~scanf("%s%s",a,b))
	{
		printf("%d\n",(int)max(fabs(a[0]-b[0]),fabs(a[1]-b[1])));
		if(a[0]<b[0])
		{
			if(a[1]>b[1])
			{
				while(a[0]<b[0]&&a[1]>b[1])
				{
					puts("RD");
					++a[0],--a[1];
				}
				while(a[0]++<b[0])puts("R");
				while(a[1]-->b[1])puts("D");
			}
			else
			{
				while(a[0]<b[0]&&a[1]<b[1])
				{
					puts("RU");
					++a[0],++a[1];
				}
				while(a[0]++<b[0])puts("R");
				while(a[1]++<b[1])puts("U");
			}
		}
		else
		{
			if(a[1]>b[1])
			{
				while(a[0]>b[0]&&a[1]>b[1])
				{
					puts("LD");
					--a[0],--a[1];
				}
				while(a[0]-->b[0])puts("L");
				while(a[1]-->b[1])puts("D");
			}
			else
			{
				while(a[0]>b[0]&&a[1]<b[1])
				{
					puts("LU");
					--a[0],++a[1];
				}
				while(a[0]-->b[0])puts("L");
				while(a[1]++<b[1])puts("U");
			}
		}
	}
	return 0;
}

第二题:给你一辆容量为v的车,往里面装一些设备,使得这些装置的容量最大

分析:第一眼看到,肯定会认为是背包问题啦,但是会发现v太大,根本没办法转移,这种情况下必然想到贪心,而且很明显,按性价比排序(也就是c/v来排序),取前面几个就行,但是有些情况会刚好剩下一格的体积,此时必须讨论,是否替换出前面的一个c最小且体积为1的装置,来放接下来这个体积为2的装置,这个还得考虑后面体积为1的装置与要替换装置的容量和,与当前这个体积为2的装置的容量,好吧,不好描述,具体看我的代码,仔细思考都不会有问题的:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int mm=111111;
struct data
{
	int v,p,id,w;
}g[mm];
int i,j,k,n,v;
long long ans;
bool cmp(data a,data b)
{
	return a.w>b.w;
}
bool cmp2(data a,data b)
{
	return a.id>b.id;
}
int main()
{
	while(~scanf("%d%d",&n,&v))
	{
		for(i=0;i<n;++i)
		{
			scanf("%d%d",&g[i].v,&g[i].p);
			g[i].id=i+1,g[i].w=g[i].p;
			if(g[i].v==1)g[i].w<<=1;;
		}
		sort(g,g+n,cmp);
		for(ans=i=j=0;i<n;++i)
			if(j+g[i].v<=v)
			{
				j+=g[i].v;
				ans+=g[i].p;
			}
			else break;
		if(j<v&&i<n)
		{
			g[n].p=0;
			for(k=i+1;k<n;++k)
				if(g[k].v==1)break;
			for(j=i-1;j>=0;--j)
				if(g[j].v==1)break;
			if(j>=0&&g[j].p+g[k].p<g[i].p)
			{
				ans+=g[i].p-g[j].p;
				swap(g[j],g[i]);
			}
			else if(k<n)
			{
				swap(g[i],g[k]);
				ans+=g[i++].p;
			}
		}
		cout<<ans<<endl;
		sort(g,g+i,cmp2);
		while(i--)printf("%d%c",g[i].id,i?' ':'\n');
	}
	return 0;
}

第三题:给你一个3*3的棋盘,两个人在上面轮流画0或者X,X先画,问当前棋盘的状况

分析:这题纯粹的分类讨论吧,假设当前有a个X,b个0,那么a<b或 a-b>1都是非法情况,接下来考虑是否有获胜情况,这个注意下三个.不是获胜(我这里wa了一次),然后就是记录是谁获胜,这里如果两个人都为获胜状态,肯定是非法的,接下来,每个人可能有2次获胜状态,不一定只有一次(这里wa了一次),然后考虑,当第一个人获胜时,a>b,否则非法;第二人获胜,则,a==b;否则非法,剩下的如果a+b==9则平局,否则若a==b,则该第二人画了

代码:

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
char map[9][9];
int i,j,a,b;
int check()
{
	for(a=b=i=0;i<3;++i)
		for(j=0;j<3;++j)
			if(map[i][j]=='X')++a;
			else if(map[i][j]=='0')++b;
	if(a<b||a-b>1)return 0;
	int s=0,t=0;
	for(i=0;i<3;++i)
		if(map[i][0]!='.'&&map[i][0]==map[i][1]&&map[i][0]==map[i][2])++s,t|=map[i][0];
	for(j=0;j<3;++j)
		if(map[0][j]!='.'&&map[0][j]==map[1][j]&&map[0][j]==map[2][j])++s,t|=map[0][j];
	if(map[1][1]!='.'&&map[0][0]==map[1][1]&&map[0][0]==map[2][2])++s,t|=map[1][1];
	if(map[1][1]!='.'&&map[0][2]==map[1][1]&&map[0][2]==map[2][0])++s,t|=map[1][1];
	if(s>0&&t==120)return 0;
	if(s>0&&a==b&&t=='X')return 0;
	if(s>0&&a>b&&t=='0')return 0;
	if(s>0)return ((t=='0')+3);
	if(a+b==9)return 5;
	if(a==b)return 1;
	return 2;
}
int main()
{
	for(i=0;i<3;++i)
		scanf("%s",map[i]);
	i=check();
	if(i==0)puts("illegal");
	if(i==1)puts("first");
	if(i==2)puts("second");
	if(i==3)puts("the first player won");
	if(i==4)puts("the second player won");
	if(i==5)puts("draw");
	return 0;
}

第四题:给你一个字符串,包含( ) ?,对于?可以花不同值变成两种括号,问至少多少值,能使得该括号表达式合法,并输出方案

分析:这题比赛时想了一个多小时也没想明白,一直往网络流方向想了,到后来觉得是贪心,但是还是没想出来,下面是看了题解后知道的。

假设(的值为1,)的值为-1,sum[i]为从1到i的括号值的和,

那么开始贪心了,从左往右扫描,遇到( 则sum加1,遇到 ) 则sum减1,遇到?呢,此时我们sum减1,并把?变成 ),在答案里加上b[i],并将当前值a[i]-b[i]还有位置i,保存起来(仔细看看a[i]-b[i],只要加上这个值,刚好就是将)改成( 了,呵呵)

当sum<0时,此时如果再不管它,就是非法的了(右括号比左括号多),那么我们在之前保存的东西,可以挽回这个情况,当然,为了使答案最小,我们取a[i]-b[i]最小的那个 ?(已经是)了) ,并且将它转化成(,之前记录位置了,答案加a[i]-b[i],sum加2。。。

就这样,最后判断sum是否为0,就行,为零就输出解了,至于怎么查找最小的值,这个用最小堆来维护就行(当然,你也可以用stl的优先队列来搞,具体我不会用,只能手写了,挫爆了T_T)

贪心+堆,挺好的!!

代码:

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
typedef long long LL;
const int mm=111111;
struct heap
{
    int v[mm],p[mm];
    int size;
    void change(int i,int j)
    {
        swap(v[i],v[j]);
        swap(p[i],p[j]);
    }
    void siftup(int k)
    {
        int i=k,j=i>>1;
        while(j>=1)
        {
            if(v[i]<v[j])
            {
                change(i,j);
                i=j,j=i>>1;
            }
            else break;
        }
    }
    void siftdown(int k)
    {
        int i=k,j=k<<1;
        while(j<=size)
        {
            if(j<size&&v[j+1]<v[j])++j;
            if(v[i]>v[j])
            {
                change(i,j);
                i=j,j=i<<1;
            }
            else break;
        }
    }
    void insert(int vv,int pp)
    {
        ++size;
        v[size]=vv;
        p[size]=pp;
        siftup(size);
    }
    void del()
    {
        if(!size)return;
        change(1,size);
        --size;
        siftdown(1);
    }
}g;
int a[mm],b[mm];
char s[mm];
int n,m;
LL ans;
LL solve()
{
    int i,j,sum=0;
    g.size=0;
    LL ret=0;
    for(m=i=0;i<n;++i)
        if(s[i]=='?')++m;
    for(i=0;i<m;++i)scanf("%d%d",&a[i],&b[i]);
    for(j=i=0;i<n;++i)
    {
        if(s[i]=='(')++sum;
        else if(s[i]==')')--sum;
        else s[i]=')',--sum,ret+=b[j],g.insert(a[j]-b[j],i),++j;
        if(sum<0)
        {
            if(g.size<=0)return -1;
            ret+=g.v[1];
            s[g.p[1]]='(';
            sum+=2;
            g.del();
        }
    }
    if(sum)return -1;
    return ret;
}
int main()
{
	while(~scanf("%s",s))
	{
	    n=strlen(s);
	    ans=solve();
	    cout<<ans<<endl;
	    if(ans!=-1)puts(s);
	}
	return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值