Codeforces Round #704 (Div. 2)

比賽地址c++

A(水題)

題目連接
數組

題目:
給出\(a\),\(b\),\(c\),求出比\(c\)大的最近的\(a\)\(b\)的倍數到\(c\)的距離spa

解析:
向上找最近倍數取最小值便可code

#include<bits/stdc++.h>
using namespace std;
/*===========================================*/

int main() {
	int T;
	LL p, a, b, c;
	scanf("%d", &T);
	while (T--) {
		scanf("%lld%lld%lld%lld", &p, &a, &b, &c);
		LL t[3] = { (p + a - 1) / a * a,(p + b - 1) / b * b ,(p + c - 1) / c * c };
		printf("%lld\n", min({ t[0],t[1],t[2] }) - p);
	}
}

B(貪心)

題目連接
排序

題目:
給出一疊牌,兩個空位(一個有牌,一個沒牌),每次能夠取出一部分牌按順序放在另外一堆上,若是要保證\(排序值\)最大,則要如何移動牌堆
排序值定義字符串

\[\sum_{i=1}^nn^{n−i}\times p_i. \]

解析:
由排序值定義可知,越大的數排在越前面這個值越大,則每次尋找出剩餘序列中最大的數,將此後的數放入另外一堆中,便可構成此序列get

#include<bits/stdc++.h>
using namespace std;

/*===========================================*/
const int maxn = 1e5 + 5;
int dat[maxn];
bool vis[maxn];

int main() {
	int T, n;
	scanf("%d", &T);
	while (T--) {
		MEM(vis, 0);
		scanf("%d", &n);
		for (int i = 0; i < n; ++i)
			scanf("%d", &dat[i]);
		int mx = n;
		int last = n;
		for (int i = n - 1; i >= 0; --i) {
			vis[dat[i]] = true;
			if (dat[i] == mx) {
				for (int j = i; j < last; ++j)
					printf("%d ", dat[j]);
				while (vis[mx])
					--mx;
				last = i;
			}
		}
		printf("\n");
	}
}

C(思惟)

題目連接
⭐⭐it

題目:
給出字符串\(s,t\),長度分別爲\(n\),\(m\),一定存在\(p\)序列,知足\(1\le p_1<p_2<\dots<p_m\le n\),而且\(s_{p_i}=t_i\),求出擁有最大相鄰元素間距的\(p\)序列ast

解析:
對於任意一個\(t\)中的字符能夠映射到\(s\)中的一些字符,求出每一個字符可以映射的最小合法距離和最大合法距離,求出\(\max_{i=2}^m(high[i]-[low[i-1]])\)class

#include<bits/stdc++.h>
using namespace std;

/*===========================================*/
const int maxn = 2e5 + 5;
char s[maxn], t[maxn];
int lens, lent;
int low[maxn], high[maxn];


int main() {
	scanf("%d%d", &lens, &lent);
	scanf("%s%s", s + 1, t + 1);
	int p = 1;
	for (int i = 1; i <= lent; ++i, ++p) {
		if (s[p] != t[i]) ++p;
		low[i] = p;
	}
	p = lens;
	for (int i = lent; i > 0; --i, --p) {
		if (s[p] != t[i]) --p;
		high[i] = p;
	}
	int mx = 0;
	for (int i = 2; i <= lent; ++i)
		mx = max(mx, high[i] - low[i - 1]);
	printf("%d", mx);
}

D(思惟)

題目連接
⭐⭐⭐

題目:
存在兩個二進制數,均有\(a\)\(0\)\(b\)\(1\),且大的二進制數減去小的二進制數有\(k\)\(1\),若這樣的一對二進制數存在,求出對應的二進制數

解析:
假設下列討論01表明同一位大數爲0,小數爲1;00表明同一位大數爲0,小數爲0...
對於00,11,10狀況,在未出現借位時,貢獻分別爲0,0 ,1
對於01時 貢獻爲1,出現借位,對後序出現的4種狀況進行討論

  • 00 貢獻爲1 繼續借位
  • 01 貢獻爲0 繼續借位
  • 11 貢獻爲1 繼續借位
  • 10 貢獻爲0 中止借位

能夠看出每對01都須要一對10來終止,且能夠確定的是01與10出現的次數相等,且花費了2個0和兩個1只能貢獻1,而若是這兩個0兩個1以00,11的形式出如今借位過程當中能夠得到更多個1
因此這對二進制數必定是如下述方式存在的

\[1\dots1|1|1\dots1|0\dots0|0|0\dots0\\ 1\dots1|0|1\dots1|0\dots0|1|0\dots0 \]

#include<bits/stdc++.h>
using std::min;

/*===========================================*/
const int maxn = 2e5 + 5;
char ret[2][maxn];
int index = 0;

int main() {
	int a, b, c;
	scanf("%d%d%d", &a, &b, &c);
	int t = min(a, b);
	if (!c || c <= a + b - 2 && !a && b != 1)
	{
		if (c)
		{
			--a, --b, --c;
			while (a + b > c && b--)
				ret[0][index] = ret[1][index] = '1', ++index;
			ret[0][index] = '1';
			ret[1][index++] = '0';
			while (a-- && c--)
				ret[0][index] = ret[1][index] = '0', ++index;
			while (c-- > 0)
				ret[0][index] = ret[1][index] = '1', ++index;
			ret[0][index] = '0';
			ret[1][index++] = '1';
			while (~(a--))
				ret[0][index] = ret[1][index] = '0', ++index;
		}
		else
		{
			for (int i = 0; i < b; ++i, ++index)
				ret[0][index] = ret[1][index] = '1';
			for (int i = 0; i < a; ++i, ++index)
				ret[0][index] = ret[1][index] = '0';
		}
		printf("%s\n%s", ret[0], ret[1]);
	}
	else
		printf("No");
}

E(思惟+搜索)

題目連接
⭐⭐⭐⭐

題目:
給出\(n\)組關於某一個長度爲\(m\)的數組的複製,每組種至多隻有兩處與原數組不一樣,判斷這樣的原數組是否存在並輸出

解析:
能夠假定第一個數組就是原數組,樸素的去統計每組數據最多的不一樣之處,進行分類討論
能夠分析第一個數組存在至多兩處不一樣,其餘數組也至多存在兩個不一樣,因此第一個數組爲假定的狀況下與其餘數組至多出現4處不一樣

總結:

  • 若是最多不一樣點小於等於2,則第一個複製數組便可做爲原數組
  • 若是不一樣點等於3,則根據不一樣點爲3的複製數組進行更改,使得這個數組的不一樣點降爲2
    • 再次進行全部複製品的判斷,若是不一樣點小於等於2,則輸出當前更改後的數組
    • 不然則再次根據不一樣點爲3的複製數組進行更改,進行全部複製品的判斷
      • 只有不一樣點小於等於2時才輸出
      • 不然則失敗
  • 若是不一樣點等於4,則\(C_4^2\)挑選兩處不一樣點進行更改,判斷可行就輸出

注意:

  1. 在不一樣點等於3時第一個數組須要更改的地方不必定只有一處
  2. 要保存好每次進行判斷檢測時最大值所在數組編號的副本,防止後序檢測後被更替
#include<bits/stdc++.h>
using namespace std;
/*===========================================*/

vector<vector<int> > dat;
int n, m;
vector<int> ret;
int dif;
int id;

void cnt() {
	dif = 0;
	for (int i = 1; i < n; ++i) {
		int c = 0;
		for (int j = 0; j < m; ++j)
			if (ret[j] != dat[i][j])
				++c;
		if (c > dif) {
			dif = c;
			id = i;
		}
	}
}

void yes() {
	printf("Yes\n");
	for_each(ret.begin(), ret.end(), [](int& i) {printf("%d ", i); });
	exit(0);
}

int main() {
	scanf("%d%d", &n, &m);
	dat.assign(n, vector<int>(m));
	for (int i = 0; i < n; ++i)
		for (int j = 0; j < m; ++j)
			scanf("%d", &dat[i][j]);
	ret.assign(dat[0].begin(), dat[0].end());
	cnt();
	if (dif <= 2) yes();
	else if (dif == 3) {
		int tmp = id;
		for (int i = 0; i < m; ++i) {
			if (dat[tmp][i] != ret[i]) {
				ret[i] = dat[tmp][i];
				cnt();
				int iid = id;
				if (dif <= 2) yes();
				else if (dif == 3) {
					for (int j = 0; j < m; ++j)
						if (dat[iid][j] != ret[j]) {
							int t = ret[j];
							ret[j] = dat[iid][j];
							cnt();
							if (dif <= 2)
								yes();
							ret[j] = t;
						}
				}
				ret[i] = dat[0][i];
			}
		}
	}
	else if (dif == 4) {
		int iid = id;
		int r[4], p = 0;
		for (int i = 0; i < m; ++i)
			if (dat[id][i] != ret[i])
				r[p++] = i;
		for (int i = 1; i < 4; ++i)
			for (int j = 0; j < i; ++j) {
				ret[r[i]] = dat[iid][r[i]];
				ret[r[j]] = dat[iid][r[j]];
				cnt();
				if (dif <= 2) yes();
				ret[r[i]] = dat[0][r[i]];
				ret[r[j]] = dat[0][r[j]];
			}
	}
	printf("No");
}
相關文章
相關標籤/搜索