CodeCraft-20 (ABCD)


CodeCraft-20 (Div. 2)


前言


比赛AC


A. Grade Allocation

简明题意

  • 有n个人,每个人有个分数,最高分是m。现在其中一个同学可以修改所有人的分数,他想使得最高分不超过m且平均分不变的情况下尽可能把自己分数修改高。问最高是多少。

正文

  • 平均分不变,等价于总分不变。直接让自己的分等于总分,其他人都0分就可以。然后和m比一下,如果比m大了就是m,否则就是总分。

代码


B. String Modification

简明题意

  • 有一个长度n<=5000的字符串,现在可以选一个k(1<=k<=n),选了k之后会依次反转原字符串的1到k,2到k+1…最终得到新的字符串。问k选几时,得到的新字符串字典序最小。

正文

  • k=2时,相当于冒泡排序,就是把a[1]移到了最后。
  • k>=2时,把1-k-1看成一个整体,这个整体会被移动到最后面。但注意每反转一次,那个整体的顺序就被颠倒一次。一共会被反转n-k+1次,所以当n-k+1是奇数时,就应该反转那个整体。
  • 所以对于每个K就能O(1)得出操作后的字符串,而1<=k<=n,相当于一个字符串O(n)就能找到答案,复杂度是够的。

代码


#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<stack>
#include<map>
#include<queue>
#include<string>
#include<vector>
using namespace std;

void solve()
{

	int t;
	cin >> t;
	while (t--)
	{
		int n;
		cin >> n;
		string a;
		cin >> a;

		string ans;
		int min_k;
		for (int k = 1; k <= n; k++)
		{
			string x = a.substr(0, k - 1);
			if ((n - k + 1) % 2 == 1) reverse(x.begin(), x.end());
			string y = a.substr(k - 1, n - k +1);
			string b = y + x;
			if (ans == "")ans = b, min_k = k;
			else if (b < ans) ans = b, min_k = k;
		}
		cout << ans << endl;
		cout << min_k << endl;
	}
}

int main()
{
	//freopen("Testin.txt", "r", stdin);
	solve();
	return 0;
}

赛后补题


C. Primitive Primes

简明题意

  • 给你两个多项式f(x)和g(x),用数组a[]给出f(x)的系数,b[]给出g(x)的系数。给出质数p,令h(x)=f(x)*g(x),现在需要你输出h(x)的任意一个不能被p整除的系数。
  • a数组两两互质,b数组也是。

正文

  • 首先得直到两个多项式乘出来是什么。假设有k和l,那么
    c x + y = i = 0 x + y a i b x + y = a 0 b x + y + a 1 b x + y 1 + . . . + a x b y + . . . + a x + 1 b y 1 + a x + y b 0 c_{x+y}=\prod_{i=0}^{x+y}a_ib_{x+y}=a_0b_{x+y}+a_1b_{x+y-1}+...+a_xb_y+...+a_{x+1}b_{y-1}+a_{x+y}b_0
  • 现在想要找到不能被p整除的一个c。 既然不能被p整除,那就让 C x + y C_{x+y} 展开后的每一项都不能被p,可以吗?不行。。。。因为加起来后可能又能被p整除了。
  • 通常做法是只让一项不能被p整除,其余全让他成为p的倍数。这样的话不能被p整除的项,就没法加上一个数使得他能被p整除。现在,我们就想要c的展开式中,只有一项不能被p整除。
  • 这里可以让 a x a_x b y b_y 不能被p整除,其余的 a 1 a x 1 a_1到a_{x-1} b 1 b x 1 b_1到b_{x-1} 全部能被p整除,这样就会发现上面的展开式中,只有 a x a y a_xa_y 这一项不能被p整除,其余全部能被c整除。那么就可以得出此时的 c x + y c_x+y 能被p整除。
  • a x a_x b y b_y 不能被p整除,其余的 a 1 a x 1 a_1到a_{x-1} b 1 b x 1 b_1到b_{x-1} 全部能被p整除。这个怎么找呢?很简单,直接遍历ab数组,找到第一个不能被p整除的数字就可以了。
  • 那么我们现在思考一下ab数组分别互质的意义。目前为止好像并没有用到这个性质。
  • 就是告诉你,ab数组不能全被p整除。因为这样的话就没答案了

代码

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<stack>
#include<map>
#include<queue>
#include<string>
#include<vector>
using namespace std;

const int maxn = 1e5 + 10;

void solve()
{
	int n, m, p;
	cin >> n >> m >> p;
	int x = -1, y = -1;
	for (int i = 1; i <= n; i++)
	{
		int t;
		scanf("%d", &t);
		if (x == -1 && t % p != 0)
		{
			x = i;
		}
	}

	for (int i = 1; i <= m; i++)
	{
		int t;
		scanf("%d", &t);
		if (y == -1 && t % p != 0)
		{
			y = i;
			break;
		}
	}

	cout << x + y - 2;
}

int main()
{
	//freopen("Testin.txt", "r", stdin);
	solve();
	return 0;
}

D. Nash Matrix

简明题意

  • 有一个n*n的矩阵。每个格子上有L、R、U、D、X五种字符,UDLR分别表示上下左右,X表示不走。
  • 现在给出每个点作为起点,最终的到达点。如果某点出发不会停下来,就是-1

正文

  • 如果(x,y)到达(a,b),说明ab一定是X。并且可以知道,(x,y)到(a,b)路径上的所有点,都应该是(a,b)。照这个思路,我们可以从(a,b)倒着搜回去,就能填好。那么怎么知道哪些点是X呢?直接判断,如果有个点(x,y)==(a,b),那么这个点就是X。
  • 接下来只剩-1的没填了。我们发现,对于-1的连通块,只要连通块内的点>=2个,我们可以把其中相邻的两个互相指向。然后其他所有的点指向这两个点就可以了。
  • 而实际上,我们可以发现,我们直接枚举-1的点,只要他周围存在一个-1,那么直接指向就可以了。这样就是对的。
  • 现在说说答案不合法的情况。有两种情况,会不合法。
  • 1.一个点-1,与他相邻的点却没有-1
  • 2。例如,点1,1的值是1,3,但1,3却是-1-1.
  • 读入不能用cin,否则tle

代码

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<stack>
#include<map>
#include<queue>
#include<string>
#include<vector>
using namespace std;

const int maxn = 1000 + 10;
const int dir[4][2] = { 1, 0, 0, 1, -1, 0, 0, -1 };

int n, gx[maxn][maxn], gy[maxn][maxn];
char ans[maxn][maxn];

int X_pos_x, X_pos_y;
void dfs(int x, int y, char k)
{
	ans[x][y] = k;
	for (int z = 0; z < 4; z++)
	{
		int tx = x + dir[z][0], ty = y + dir[z][1];
		if (tx >= 0 && tx <= n && ty >= 0 && ty <= n && ans[tx][ty] == 0 && gx[tx][ty] == X_pos_x && gy[tx][ty] == X_pos_y)
		{
			if (z == 0) dfs(tx, ty, 'U');
			if (z == 1) dfs(tx, ty, 'L');
			if (z == 2) dfs(tx, ty, 'D');
			if (z == 3) dfs(tx, ty, 'R');
		}
	}
}

void solve()
{
	cin >> n;
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= n; j++)
			scanf("%d%d", &gx[i][j], &gy[i][j]);

	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= n; j++)
			if (i == gx[i][j] && j == gy[i][j])
			{
				X_pos_x = i, X_pos_y = j;
				dfs(i, j, 'X');
			}

	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= n; j++)
			if (ans[i][j] == 0 && gx[i][j] == -1)
			{
				bool ok = 0;
				int x = i, y = j;
				for (int z = 0; z < 4; z++)
				{
					int tx = x + dir[z][0], ty = y + dir[z][1];
					if (gx[tx][ty] == -1)
					{
						if (z == 0) ans[x][y] = 'D';
						if (z == 1) ans[x][y] = 'R';
						if (z == 2) ans[x][y] = 'U';
						if (z == 3) ans[x][y] = 'L';
						ok = 1;
					}
				}
				if (!ok)
				{
					cout << "INVALID";
					return;
				}
			}

	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= n; j++)
			if (ans[i][j] == 0)
			{
				cout << "INVALID";
				return;
			}

	cout << "VALID" << endl;
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= n; j++)
		{
			printf("%c", ans[i][j]);
				if (j == n) printf("\n");
		}
}

int main()
{
	//freopen("Testin.txt", "r", stdin);
	solve();
	return 0;
}


E. Team Building

简明题意

  • 共有n个人,现在从中选p个人作为参赛选手,k个人作为观众。
  • 第i个人作为参赛选手可以获得a[i]分,第i个人作为观众坐在第j个位置可以获得s[i][j]分。现在需要你最大化这个得分。

正文

代码


总结

发布了122 篇原创文章 · 获赞 44 · 访问量 6971

猜你喜欢

转载自blog.csdn.net/weixin_42431507/article/details/104674956
今日推荐