A: B +/- A

  • 签到题.

B: Foods Loved by Everyone

  • 签到题.

C: Monsters Battle Royale

  • 怪物的血量一直两两相减,类似于辗转相减法.
  • 可以证明,最后存活怪物血量最小值即为所有怪物初始血量的 \(gcd\) .

D: Match Matching

  • 考虑 \(dp\) 预处理一个数组 \(f\) , \(f[i][j]\) 表示第一位用数字 \(i\) ,后面一共用 \(j\) 根火柴棒,能拼出数字的最大位数.
  • 一共有 \(nm\) 个状态,每次转移 \(O(m)\) ,这个 \(dp\) 的时间复杂度为 \(O(nm^2)\).
  • 得到 \(f\) 数组后,考虑从高位到低位贪心构造解.
  • 每次都选能使后面位数最大的数字作为当前的这一位,若后面位数相同,则选数字大的.
  • 最终答案显然不会超过 \(n\) 位,确定每一位只需比较 \(m\) 个数字的优劣.这一步时间复杂度为 \(O(nm)\) .
  • 总时间复杂度为 \(O(nm^2)\) .
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define inf 1e9
inline int read()
{
	int x=0;
	bool pos=1;
	char ch=getchar();
	for(;!isdigit(ch);ch=getchar())
		if(ch=='-')
			pos=0;
	for(;isdigit(ch);ch=getchar())
		x=x*10+ch-'0';
	return pos?x:-x;
}
int x[11]={0,2,5,5,4,5,6,3,7,6};
int a[11],m,N;
const int MAXN=1e4+10;
int f[11][MAXN];
int n;
int dfs(int i,int j)
{
	if(f[i][j]!=-1)
		return f[i][j];
	if(j==0)
		return 1;
	if(j<0)
		return -inf;
	f[i][j]=-inf;
	for(int k=1;k<=m;++k)
		{
			if(j>=x[a[k]])
				f[i][j]=max(f[i][j],1+dfs(i,j-x[a[k]]));
		}
	return f[i][j];
}
bool better(int i,int j,int k)
{
	if(i-x[a[j]]<0)
		return false;
	if(!k)
		return true;
	if(f[a[j]][i-x[a[j]]]>f[a[k]][i-x[a[k]]])
		return true;
	if(f[a[j]][i-x[a[j]]]==f[a[k]][i-x[a[k]]] && a[j]>a[k])
		return true;
	return false;
}
int main()
{
	n=read(),m=read();
	memset(f,-1,sizeof f);
	for(int i=1;i<=m;++i)
		a[i]=read();
	int i,j,k;
	for(int i=1;i<=m;++i)
		dfs(a[i],n-x[a[i]]);
	for(i=n;i;)
		{
			k=0;
			for(j=1;j<=m;++j)
				if(better(i,j,k))
					k=j;
			i-=x[a[k]];
			putchar(a[k]+'0');
		}
	return 0;
}

相关文章: