Codeforces Beta Round #3 题解

78 阅读2分钟

比赛链接

A

太水,略。

B

思路

以下只讨论不能全部放入的情况。
刚开始以为是01背包问题,但是数据太大,而且物品的花费只有两种:11(称为AA)或22(称为BB)。两个AA可以合并成一个BB。把AA从大到小组对合并到BB中,那最后只剩下00个或11AA,对新得到的BB按照价值大小排序,从大到小放入背包。
如果vv为偶数,就尽可能放BB。如果vv为奇数,一直放BB必定会剩下大小为11的空间,那就首先把原先AA中价值最大的放入,转化成vv为偶数的情况再求解。

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define rep(i,st,ed) for(ll i=st;i<=ed;++i)
const ll N=1E5+10;
ll n,v,ans,cnta,cntb,cnt;
ll answ[N];
struct Node{
	ll ti[2],val;
	bool operator < (const Node &tmp) const
	{
		return val>tmp.val;
	}
}a[N],b[N];
int main()
{
	scanf("%lld %lld",&n,&v);
	rep(i,1,n)
	{
		ll ty,val;
		scanf("%lld %lld",&ty,&val);
		if(ty==1)
		{
			a[++cnta].val=val;
			a[cnta].ti[0]=i;
		}
		else
		{
			b[++cntb].val=val;
			b[cntb].ti[0]=i;
		}
	}
	sort(a+1,a+cnta+1);
	if(v%2)
	{
		ans+=a[1].val;
		answ[++cnt]=a[1].ti[0];
	}
	for(ll i=1+v%2;i<=cnta;i+=2)
	{
		b[++cntb].val=a[i].val+a[i+1].val;
		b[cntb].ti[0]=a[i].ti[0];
		b[cntb].ti[1]=a[i+1].ti[0];
	}
	sort(b+1,b+cntb+1);
	ll n=min(v/2,cntb);
	rep(i,1,n)
	{
		ans+=b[i].val;
		answ[++cnt]=b[i].ti[0];
		if(b[i].ti[1])
			answ[++cnt]=b[i].ti[1];
	}
	cout<<ans<<endl;
	if(ans)
		rep(i,1,cnt)
			printf("%lld ",answ[i]);
	cout<<endl;
}

C

思路

A和B下三子棋,A先手,非法情况特别多

  • A比B多走两步及以上
  • B比A多走一步及以上
  • A胜利但是和B走的步数是一样的
  • B胜利但是比A少走了一步 剩下的不难写。

代码

#include<bits/stdc++.h>
#define rep(i,st,ed) for(int i=st;i<=ed;++i)
using namespace std;
int cnta,cntb;
int a[5][5];
string s;
int judge(int val)
{
	int ret=0;
	rep(i,1,3)
	{
		int tot=0;
		rep(j,1,3)
		{
			if(a[i][j]==val)
				++tot;
		}
		if(tot==3)
			++ret;
	}
	rep(i,1,3)
	{
		int tot=0;
		rep(j,1,3)
		{
			if(a[j][i]==val)
				++tot;
		}
		if(tot==3)
			++ret;
	}
	if(a[2][2]==val)
	{
		if(a[1][1]==val && a[3][3]==val)
			++ret;
		if(a[1][3]==val && a[3][1]==val)
			++ret;
	}
	return ret;
}
int main()
{
	rep(i,1,3)
	{
		cin>>s;
		rep(j,0,2)
		{
			if(s[j]=='X')
			{
				a[i][j+1]=1;
				++cnta;
			}
			else if(s[j]=='0')
			{
				a[i][j+1]=2;
				++cntb;
			}
			else
			{
				a[i][j+1]=0;
			}
		}
	}
	if(cntb>cnta || cntb<cnta-1)
	{
		puts("illegal");
		return 0;
	}
	if(judge(2) && cnta>cntb)
	{
		puts("illegal");
		return 0;
	}
	if(judge(1) && cnta==cntb)
	{
		puts("illegal");
		return 0;
	}
	if(judge(1))
	{
		puts("the first player won");
		return 0;
	}
	if(judge(2))
	{
		puts("the second player won");
		return 0;
	}
	if(cnta+cntb==9)
	{
		puts("draw");
		return 0;
	}
	if(cnta>cntb)
		puts("second");
	else
		puts("first");
}

D

思路

扫一遍字符串,遇到'?'就改成')',按照每个'?'变成')’和变成'(‘的差值(即rlr-l)作为关键字维护一个大根堆,如果出现了右括号不匹配的情况就取出堆顶元素并将其变为'('(因为是大根堆,所以取堆顶元素能够减去的代价会更多),更新答案。

代码

#include<bits/stdc++.h>
#define rep(i,st,ed) for(int i=st;i<=ed;++i)
using namespace std;
typedef long long ll;
const int N=5E4+10;
int m,k,cnt;
int is[N],dis[N];
ll ans;
struct Node{
	ll l,r,pos;
	bool operator < (const Node &tmp) const
	{
		return r-l<tmp.r-tmp.l;
	}
};
priority_queue<Node> q;
int main()
{
	string s;
	cin>>s;
	s=' '+s;
	int n=s.size()-1;
	rep(i,1,n)
	{
		if(s[i]=='(')
			++cnt;
		if(s[i]=='?')
		{
			ll l,r;
			scanf("%lld %lld",&l,&r);
			if(i==1)
			{
				ans+=l;
				s[i]='(';
				++cnt;
				continue;
			}
			s[i]=')';
			ans+=r;
			q.push((Node){l,r,i});
		}
		if(s[i]==')')
		{
			if(cnt)
				--cnt;
			else
			{
				if(!q.empty())
				{
					Node cur=q.top();
					q.pop();
					if(cur.pos==n)
					{
						cur=q.top();
						q.pop();
					}
					ans-=cur.r;
					ans+=cur.l;
					s[cur.pos]='(';
					++cnt;
				}
				else
				{
					cout<<"-1"<<endl;
					return 0;
				}
			}
		}
	}
	if(cnt)
	{
		cout<<-1<<endl;
		return 0;
	}
	cout<<ans<<endl;
	rep(i,1,n)
		putchar(s[i]);
	putchar('\n');
}