电子科技大学第十届ACM趣味程序设计竞赛第四场(正式赛)官方题解

https://lutece.xyz/contest/detail/9/

A

source:别问,问就

题目要找到创世神最少需要抽取的经验等级数,很明显对于两种更改等级方式来说,第一种方式是优先选择的方式。

所以利用贪心思想,我们只需要找到低于k的玩家的等级与k之间的差总和x和高于k的玩家的等级与k之间的差总和y,如果x-y大于零,则输出x-y,表明仍需创世神抽出x-y等级的经验值,否则输出0即可,表明不需要创世神再抽出经验值。

当然,在代码实现时可以在读入n个整数时计算k-a,所有的k-a相加后如果为负数则输出0,否则输出求和后的值便可。

#include
using namespace std;
int main()
{
	int n,k,ans=0,num;
	scanf("%d%d",&n,&k);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&num);
		ans+=k-num;
	}
	if(ans<0) printf("0\n");
	else printf("%d\n",ans);	
	return 0; 
} 

B

source:sindar

由于气球碰撞之后交换速度,我们可以看做它们交换了位置,所以只需要分别算出每个气球到达烟囱顶部的时间,取max和min就可以了

#include
#include
#include
#include
using namespace std;

const int maxn=100000+10;

double h[maxn],a[maxn];

int main()
{
	int n,L,v;cin>>n>>L>>v;
	
	double N=1e18,M=0;
	for (int i = 1; i <= n; i++) {
		scanf("%lf%lf",h+i,a+i);
		N=min(N,(1.0*L-h[i])/(v+a[i]));
		M=max(M,(1.0*L-h[i])/(v+a[i]));
	} 
	printf("%.2f %.2f\n",N,M);
	return 0;
}

C

source:zyx

多写几行

t=0 1

t=1 1/2 0 1/2

t=2 1/4 0 2/4 0 1/4

t=3 1/8 0 3/8 0 3/8 0 1/8

​ …

我们就能发现,把每一项乘以 2^t ,就成了一个杨辉三角形,即对于 t=x 时,蚂蚁出现在位置 y 的概率P(X,Y)=P(X-1,Y-1)+P(X-1,Y+1),而除了杨辉三角外的项,其余项概率皆为 0。那么我们需要计算的就是一个杨辉三角和 2^t 的值,因为 t<=30 ,刚好用 int 就能装下.知道了这些,接下来就是一个简单的递推,不过最后输出前记得化简。还有需要注意的是 t=0,m=0 时,概率为 1 ,因为 1 是整数,所以直接输出 1 ,而不是 1/1 (题目描述为:若结果不是整数,则以x/y的形式输出)。

#include 

int x[22][200];
int y[22];
int main()
{
	int t,m,T,p,q;
	y[0] = 1;
	x[0][1] = 1;
	for (int i=1;i<=20;i++)
	{
		y[i]=y[i-1] * 2;
		for (int j=1;j<=i+1;j++)
		   x[i][j]=x[i-1][j-1] + x[i-1][j+1];
		   
		x[i][0]=x[i][2];
	}
	scanf("%d\n",&T);
	while (T--)
	{
		scanf("%d%d\n",&t,&m);
		if (m < 0) m= -m; 
		
		if (m > t|| x[t][m + 1]==0){ printf("0\n"); continue; }
		if (t==0){ printf("%d\n",x[t][m+1]); continue; } 
		
		p=x[t][m + 1];
		q=y[t];
		while (p % 2==0)
		{
			p= p/2;
			q= q/2;
		}
		
		printf("%d/%d\n",p,q);
	}
	return 0;
} 

另外,题目要求给出既约分数,但分母是二的次幂,所以不需要特意用求GCD的算法,直接除2即可。
以上是本题的递推式写法。注意到答案和杨辉三角有关系后,应该想到可以用高中学的组合数解题。
20!在long long int能够表示的范围内,所以可以直接计算。

#include 
using namespace std;

long long fac (long long x) {
	long long ret = 1;
	for (int i = 1; i <= x; i++) ret *= i;
	return ret;
}

long long Pow (long long x) {
	long long ret = 1;
	for (int i = 1; i <= x; i++) ret <<= 1;
	return ret;
}

int main (void) {
	int kase, t, m;
	scanf("%d", &kase);
	while (kase--) {
		scanf("%d%d", &t, &m);
		if (((t + m) % 2 == 0) && abs(m) <= t) {
			long long p = fac(t) / fac((m + t) / 2) / fac((t - m) / 2);
			long long q = Pow(t);
			while (p % 2 == 0) {
				p >>= 1;
				q >>= 1;
			}
			if (q != 1) printf("%lld/%lld\n", p, q);
			else printf("%lld\n", p);
		} else {
			printf("0\n");
		}
	}
}

D

source:SinGinHung

https://www.cnblogs.com/siuginhung/

一条 Hamilton 路径从 v 0 v_0 v0 依次通过点 v 0 , v 1 , v 2 , ⋯   , v k v_0,v_1,v_2,\cdots,v_k v0,v1,v2,,vk ,最终到达点 v k v_k vk ,且点 v i − 1 v_{i-1} vi1 与点 v i v_i vi 之间的距离为 e i e_i ei ,则这条 Hamilton 路径的长度为 e 1 ⊕ e 2 ⊕ ⋯ ⊕ e k e_1\oplus e_2\oplus\cdots\oplus e_k e1e2ek ;其中, e i = v i − 1 ⊕ v i e_i=v_{i-1}\oplus v_i ei=vi1vi 。于是,路径的长度为: ( v 0 ⊕ v 1 ) ⊕ ( v 1 ⊕ v 2 ) ⊕ ⋯ ⊕ ( v k − 1 ⊕ v k ) (v_0\oplus v_1)\oplus(v_1\oplus v_2)\oplus\cdots\oplus(v_{k-1}\oplus v_k) (v0v1)(v1v2)(vk1vk),即 v 0 ⊕ ( v 1 ⊕ v 1 ) ⊕ ( v 2 ⊕ v 2 ) ⊕ ⋯ ⊕ ( v k − 1 ⊕ v k − 1 ) ⊕ v k v_0\oplus(v_1\oplus v_1)\oplus(v_2\oplus v_2)\oplus\cdots\oplus(v_{k-1}\oplus v_{k-1})\oplus v_k v0(v1v1)(v2v2)(vk1vk1)vk

根据异或运算的规则,可以得到异或运算的一个基本规律: a ⊕ a = 0 a\oplus a=0 aa=0 。于是,上式可以化简为 v 0 ⊕ v k v_0\oplus v_k v0vk 。可见,这个值只与起止点有关,而与中间路过的点无关。

于是,在编号为 0 , 1 , 2 , ⋯   , n 0,1,2,\cdots,n 0,1,2,,n 的图中, u → v u\rightarrow v uv 的 Hamilton 路径的长度为 u ⊕ v u\oplus v uv 。本题的答案即是求解 u ⊕ v u\oplus v uv 的最大值,其中 0 ≤ u , v ≤ n 0\le u,v\le n 0u,vn ,且 u ≠ v u\ne v u̸=v 。此时,依靠枚举,似乎已经可以解决这个问题了。但是在 1 ≤ n ≤ 1 0 5 ​ 1\le n\le 10^5​ 1n105 的数据范围下,将可能会 TLE 。

以下考虑从数学上更为高效地求解这个问题。

考虑是否可以将 n n n 的所有可用的二进制位(即最高的 ′ 1 ′ '1' 1 位以下的二进制位)均变为 1 1 1 。不妨设变换后的这个数为 S S S 。设 n n n 的最高可用位数为 b − 1 b-1 b1 ,则 S = 2 b − 1 S=2^b-1 S=2b1 。考虑是否存在 u u u v v v ,使得 u ⊕ v = S u\oplus v=S uv=S。如果解存在,则 S S S 即为异或可以达到的最大值。

由于 0 ≤ u , v ≤ n 0\le u,v\le n 0u,vn ,且 S S S 的所有可用位均为 1 1 1 ,故 u + v = S u+v=S u+v=S 。这个解显然是存在的。

之后,考虑字典序最小化条件。为使得 u u u 的值尽可能小,则应当使得 v v v 的值尽可能大。于是 u u u v v v 的一组解为 u = S − n u=S-n u=Sn v = n v=n v=n 。由于 2 b − 1 ≤ n ≤ 2 b − 1 2^{b-1}\le n\le 2^b-1 2b1n2b1 ,故 u = S − n < 2 b − n ≤ 2 b − 1 ≤ n = v u=S-n<2^b-n\le 2^{b-1}\le n=v u=Sn<2bn2b1n=v ,即 u < v u<v u<v

之前提到,路径长度与中间经过的点无关,则将中间经过的点从小到大排列即可。

参考程序如下:

#include 

int main(int argc, char* argv[])
{
	int n;
	scanf("%d", &n);
	int bit = 0;
	for (; n >> bit; bit++) {}
	int ans = (1 << bit) - 1;
	printf("%d\n", ans);
	int u = ans - n;
	int v = n;
	printf("%d ", u);
	for (int i = 0; i <= n; i++) {
		if (i != u && i != v) {
			printf("%d ", i);
		}
	}
	printf("%d\n", v);
	return 0;
}

E

source:QYiTong1smyboss

首先我们把题目翻译成人话,设有数列
k 0 , k 0 ⋯   , k 0 , k 1 , k 1 , ⋯   , k 1 , k 2 , k 2 , ⋯   , k 2 , ⋯   , k n − 1 , k n − 1 , ⋯ k n − 1 k^0,k^0\cdots ,k^0,k^1,k^1,\cdots ,k^1,k^2,k^2,\cdots,k^2,\cdots ,k^{n-1},k^{n-1},\cdots k^{n-1} k0,k0,k0,k1,k1,,k1,k2,k2,,k2,,kn1,kn1,kn1
对 于 自 然 数 m ( 1 ≤ m ≤ k n − 1 ) , 用 数 列 中 不 同 位 置 的 某 些 项 之 和 来 表 示 m 的 方 法 数 记 为 a m , 设 数 列 各 项 和 为 S 对于自然数m(1\leq m\leq k^n-1),用数列中不同位置的某些项之和来表示m的方法数记为a_m,设数列各项和为S m(1mkn1),mam,S
请 你 求 出 a 1 + a 2 + a 3 + ⋯ + a S 请你求出a_1+a_2+a_3+\cdots+a_S a1+a2+a3++aS
注 意 到 k 0 + k 0 + ⋯ + k 0 + k 1 + k 1 + ⋯ + k 1 + k 2 + k 2 + ⋯ + k 2 + ⋯ + k n − 1 + k n − 1 + ⋯ + k n − 1 = k n − 1 注意到k^0+k^0+\cdots+k^0+k^1+k^1+\cdots+k^1+k^2+k^2+\cdots+k^2+\cdots +k^{n-1}+k^{n-1}+\cdots+k^{n-1}=k^n-1 k0+k0++k0+k1+k1++k1+k2+k2++k2++kn1+kn1++kn1=kn1
设 P n = a 1 + a 2 + ⋯ + a k n − 1 设P_n=a_1+a_2+\cdots+a_{k^n-1} Pn=a1+a2++akn1
对于(k-1)(n+1)项数列
k 0 , k 0 ⋯   , k 0 , k 1 , k 1 , ⋯   , k 1 , k 2 , k 2 , ⋯   , k 2 , ⋯   , k n − 1 , k n − 1 , ⋯ k n − 1 , k n , k n , ⋯   , k n k^0,k^0\cdots ,k^0,k^1,k^1,\cdots ,k^1,k^2,k^2,\cdots,k^2,\cdots ,k^{n-1},k^{n-1},\cdots k^{n-1},k^n,k^n,\cdots,k^n k0,k0,k0,k1,k1,,k1,k2,k2,,k2,,kn1,kn1,kn1,kn,kn,,kn
设 用 前 面 ( k − 1 ) n 项 表 示 1 至 k n − 1 的 自 然 数 方 法 之 和 为 P n , 若 自 然 数 1 ≤ m ≤ ( k n − 1 ) , 设用前面(k-1)n项表示1至k^n-1的自然数方法之和为P_n,若自然数1\leq m\leq(k^n-1), (k1)n1kn1Pn,1m(kn1),
m 用 数 列 中 前 n ( k − 1 ) 项 表 示 有 a m 种 方 法 , 则 自 然 数 m + k n 用 上 述 数 列 表 示 就 有 C ( k − 1 , 1 ) ∗ a m 种 方 法 , ⋯ m用数列中前n(k-1)项表示有a_m种方法,则自然数m+k^n用上述数列表示就有C(k-1,1)*a_m种方法,\cdots mn(k1)am,m+knC(k1,1)am,
m + 2 ∗ k n 有 C ( k − 1 , 2 ) ∗ a m 种 方 法 ⋯ m + ( k − 1 ) × k n 用 上 述 数 列 表 示 有 C ( k − 1 , k − 1 ) ∗ a m 种 方 法 m+2*k^n有C(k-1,2)*a_m种方法\cdots m+(k-1)\times k^n用上述数列表示有C(k-1,k-1)*a_m种方法 m+2knC(k1,2)amm+(k1)×knC(k1,k1)am
此 外 易 得 a k n = C ( k − 1 , 1 ) , a 2 × k n = C ( k − 1 , 2 ) , ⋯   , a ( k − 1 ) k n = C ( k − 1 , k − 1 ) 此外易得a_{k^n}=C(k-1,1),a_{2\times k^n}=C(k-1,2),\cdots,a_{(k-1)k^n}=C(k-1,k-1) akn=C(k1,1),a2×kn=C(k1,2),,a(k1)kn=C(k1,k1)
所 以 P n + 1 = P n + P n ∗ ( 2 k − 1 − 1 ) + ( 2 k − 1 − 1 ) 所以P_{n+1}=P_n+P_n*(2^{k-1}-1)+(2^{k-1}-1) Pn+1=Pn+Pn(2k11)+(2k11)
再 算 出 P 1 = C ( k − 1 , 1 ) + C ( k − 1 , 2 ) + ⋯ + C ( k − 1 , k − 1 ) = 2 k − 1 − 1 ( 以 上 C 为 组 合 数 公 式 ) 再算出P_1=C(k-1,1)+C(k-1,2)+\cdots+C(k-1,k-1)=2^{k-1}-1(以上C为组合数公式) P1=C(k1,1)+C(k1,2)++C(k1,k1)=2k11(C)
推 出 P n = 2 n ( k − 1 ) − 1 , 不 难 看 出 该 数 的 二 进 制 表 示 为 连 续 的 n ∗ ( k − 1 ) 个 ′ 1 ′ 推出P_n=2^{n(k-1)}-1,不难看出该数的二进制表示为连续的n*(k-1)个'1' Pn=2n(k1)1,n(k1)1

所以以下就是本题的代码:

for (int i = 1; i <= n*(k-1); i++)
		printf("1");

SAuppp(ljp):
当K = 3,有N种衣服那么穿衣状态就可以用长度为N的三进制数表示

比如N为3
那么搭配方案就是有(除去000)
001 002 010 011 012 020 021 022
100 101 102 110 111 112 120 121 122
200 201 202 210 211 212 220 221 222
26种(三进制下的1到 3 N − 1 3^N-1 3N1

那么注意到当某一位是0 或 2 ,那就是两件全不穿 或者全穿 (方案数*1

如果某一位是1 , 那就有两种可能 : 穿这一种的第一件, 或者是另外一件 (方案数*2

举个栗子: 210这个状态 , 就有2种表示方式( 1 ∗ 2 ∗ 1 1*2*1 121)(第一种两件都穿 第二种穿第一件 第三种都不穿)(第一种两件都穿 第二种穿第二件 第三种都不穿)
而 112 就有4种方式 ( 2 ∗ 2 ∗ 1 2*2*1 221) (略)

然后, 运用高中数学知识
答案就应该是 : 枚举1的数量 , 再组合一下1的位置; 再枚举剩下的0的数量,在组合0的位置; 剩下的就全是2
然后写出来就是
∑ i = 0 N [ C N i ∗ 2 i ∗ ∑ j = 0 N − i ( 1 j ∗ 1 ( N − i ) − j ) ] \sum_{i = 0}^{N} [C_{N}^{i} * 2^i * \sum_{j = 0}^{N - i} (1^j * 1^{(N-i)-j})] i=0N[CNi2ij=0Ni(1j1(Ni)j)]
这个式子用二项式展开化简一下
∑ i = 0 N [ C N i ∗ 2 i ∗ 2 N − i ] = 4 N \sum_{i = 0}^{N} [C_{N}^{i} * 2^i * 2^{N-i}] =4^N i=0N[CNi2i2Ni]=4N

再减去裸奔的情况 4 N − 1 4^N - 1 4N1,要求输出二进制,那么就直接输出2N个1就完事了
当k = 4,同理
∑ i = 0 N C N i 3 i ∑ j = 0 N − i C N − i j 3 j ∑ k = 0 N − i − j C N − i − j k 1 k ∑ l = 0 N − i − j − k C N − i − j − k l 1 l \sum_{i = 0}^{N}C_N^i 3^i \sum_{j = 0}^{N - i}C_{N - i}^j3^j \sum_{k = 0}^{N - i -j}C_{N - i-j}^k 1^k \sum_{l = 0}^{N - i - j - k}C_{N - i - j - k}^l 1^l i=0NCNi3ij=0NiCNij3jk=0NijCNijk1kl=0NijkCNijkl1l
二项式展开化简为 8 N 8^N 8N,再减去裸奔 2 3 N − 1 2^{3N} - 1 23N1
k=5 略

你可能感兴趣的:(电子科技大学第十届ACM趣味程序设计竞赛第四场(正式赛)官方题解)