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,那麼
    cx+y=i=0x+yaibx+y=a0bx+y+a1bx+y1+...+axby+...+ax+1by1+ax+yb0c_{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整除,那就讓Cx+yC_{x+y}展開後的每一項都不能被p,可以嗎?不行。。。。因爲加起來後可能又能被p整除了。
  • 通常做法是隻讓一項不能被p整除,其餘全讓他成爲p的倍數。這樣的話不能被p整除的項,就沒法加上一個數使得他能被p整除。現在,我們就想要c的展開式中,只有一項不能被p整除。
  • 這裏可以讓axa_xbyb_y不能被p整除,其餘的a1ax1a_1到a_{x-1}b1bx1b_1到b_{x-1}全部能被p整除,這樣就會發現上面的展開式中,只有axaya_xa_y這一項不能被p整除,其餘全部能被c整除。那麼就可以得出此時的cx+yc_x+y能被p整除。
  • axa_xbyb_y不能被p整除,其餘的a1ax1a_1到a_{x-1}b1bx1b_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]分。現在需要你最大化這個得分。

正文

代碼


總結

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章