Codeforces Round #641 div2 ABCDE & 1ABC

l比赛题目链接

A.Orac and Factors

题意:给你一个数每次递归地加上它自己的最小非1因数,问 k k k次之后这个数是多少?

思路:偶数一直加2,奇数先找到最小因数,加上后一定是个偶数,然后一直加2。

#include 
const int MAXN = 1e5 + 10;
typedef long long ll;
using namespace std;
 
 
int main() {
	int T;
	cin >> T;
	while (T--) {
		ll n, k;
		cin >> n >> k;
		if (n & 1) {
			for (int i = 3; ; i++) {
				if (n % i == 0) {
					n += i;
					break;
				}
			}
			n = n + (k - 1) * 2ll;
		}
		else {
			n = n + k * 2ll;
		}
		cout << n << endl;
	}
}

B.Orac and Models

题意:给你一个数列,让你从中选取一个严格上升的子序列,且对于子序列中的任意两个下标 i , j ( i < j ) i,j(ii,j(i<j),在原序列中的下标 p i , p j ( p i < p j ) p_i,p_j(p_ipi,pj(pi<pj),都有 p j p_j pj整除 p i p_i pi,问这样的子序列长度最长是多少?。

思路:定义 d p [ i ] dp[i] dp[i]为原序列前 i i i个数的最长答案,有转移: d p [ j ] = m a x { d p [ i ] + 1 }   i f ( i ∣ j   &   a [ j ] > a [ i ] ) dp[j] = max\{dp[i] + 1\} \ if(i|j \ \&\ a[j]>a[i] ) dp[j]=max{dp[i]+1} if(ij & a[j]>a[i]),复杂度 O ( n l o g ( n ) ) O(nlog(n)) O(nlog(n))。ps:比赛的时候我dfs写的,又丑又长还会wa。。。。

#include 
typedef long long ll;
using namespace std;
const int MAXN = 1e5 + 10;
const int INF = 0x3f3f3f3f;
 
int a[MAXN];
int dp[MAXN];
 
int main() {
	int T;
	cin >> T;
	while (T--) {
		int n;
		cin >> n;
		for (int i = 1; i <= n; i++) {
			cin >> a[i];
			dp[i] = 1;
		}
		int ret = 1;
		for (int i = 1; i <= n; i++) {
			for (int j = 2 * i; j <= n; j += i) {
				if (a[j] > a[i]) {
					dp[j] = max(dp[j], dp[i] + 1);
					ret = max(ret, dp[j]);
				}	
			}
		}
		cout << ret << endl;
	}
}

C.Orac and LCM

题意:求任两个数的lcm的gcd

思路:设素数 p p p,假设最后的答案有 p k p^k pk这样一个因子,那么 p k p^k pk至少是原来的 n − 1 n-1 n1个数的因子。反证法可以证明。那么之后只要将所有的数进行因式分解,之后记录并统计一下各个素数出现的次数即可。

另一种做法(题解):每次求出除了当前数外其他数的gcd(用前后缀)。最后再求这些gcd的lcm即为答案,这种做法可以使得数的范围更大~1e9,上个做法应该只能1e6左右。

#include 
const int MAXN = 1e5 + 10;
typedef long long ll;
using namespace std;
const int N = 1e5 + 10;
int dp[N];
const int INF = 0x3f3f3f3f;
 
 
#define pa pair
 
const int maxn = 1e6 + 1000;
int prime[maxn] = { 0 }, phi[maxn] = { 0 }, tot = 0;
 
void euler() {
	phi[1] = 1;
	for (int i = 2; i < maxn; i++) {
		if (!phi[i]) {
			prime[tot++] = i;
			phi[i] = i - 1;
		}
		for (int j = 0; j < tot && i * prime[j] < maxn; j++) {
			if (i % prime[j] == 0) {
				phi[i * prime[j]] = phi[i] * prime[j];
				break;
			}
			phi[i * prime[j]] = phi[i] * phi[prime[j]];
		}
	}
}
map<int, vector<int>> ma;
 
#define pa pair
vector<pa> factor;
void init(int n) {
	factor.clear();
	for (int i = 0; prime[i] * prime[i] <= n && i < tot; i++) {
		if (n % prime[i] == 0) {
			factor.emplace_back(prime[i], 0);
			for (; n % prime[i] == 0; n /= prime[i]) factor.back().second++;
		}
	}
	if (n > 1) factor.emplace_back(n, 1);
 
	for (auto it : factor) {
		ma[it.first].push_back(it.second);
	}
}
 
int arr[MAXN];
int main() {
	euler();
	cin.tie(0);
	ios::sync_with_stdio(0);
	int n;
	while (cin >> n) {
		ma.clear();
		for (int i = 1; i <= n; i++) {
			cin >> arr[i];
			init(arr[i]);
		}
		
		ll ret = 1;
		for (auto& it : ma) {
			int tt = 0;
			if (it.second.size() == n) {
				sort(it.second.begin(), it.second.end());
				tt = it.second[1];
 
			}
			else if (int(it.second.size()) == n - 1) {
				sort(it.second.begin(), it.second.end());
				tt = it.second[0];
			}
			
			for (int i = 0; i < tt; i++) ret *= ll(it.first);
		}
 
		cout << ret << endl;
	}
}

D.Orac and Medians

题意:一个数组,每次选择一个区间,将他们都变为这个区间的中位数(偶数个的时候中位数取较小的那个),问最后能否把整个数组都变成 k k k

思路:首先判断有没有 k k k,没 k k k那是肯定不行的,接着看下每连着的三个数是不是有两个都大于等于k就行了。因为一个小数可以直接把它隔壁的大数拖下水,而大数要两个以上才能不断把小数变大。比赛时候看错题了,一下子没思路,而且朋友叫我去打lol去了草。
#include 
typedef long long ll;
using namespace std;
const int MAXN = 1e5 + 10;
const int INF = 0x3f3f3f3f;
int a[MAXN];
int main() {
	int T;
	cin >> T;
	while (T--) {
		int n, k;
		cin >> n >> k;
		int kf = 0;
		for (int i = 0; i < n; i++) {
			cin >> a[i];
			if (a[i] == k) kf = 1;
		}
		if (n == 1 || n == 2) {
			if (n == 2) sort(a, a + 2);
			if (a[0] == k) cout << "yes\n";
			else cout << "no\n";
		}
		else {
			int f = 0;
			for (int i = 2; i < n; i++) {
				vector<int> t = { a[i], a[i - 1],a[i - 2] };
				sort(t.begin(), t.end());
				if (t[1] >= k && t[2] >= k) {
					f = 1;
					break;
				}
			}
			if (f && kf) cout << "yes\n";
			else cout << "no\n";
		}
	}
}

E.Orac and Game of Life

题意:给你方格的初始细胞状态(0或1),当周围细胞有和自己状态一样时,会改变状态(1->0&0->1),否则维持当前状态不变,然后每次问题在 t t t时刻 ( x , y ) (x,y) (x,y)细胞是0还是1。

思路:一个细胞开始变改变状态后,就停不下来了(因为周围和它一起变),所以只要bfs统计一下每个细胞是从什么时候开始变色的就行了。ps:我觉得这比D简单多了。

#include 
typedef long long ll;
using namespace std;
const int MAXN = 1e3 + 10;
const ll INF = 2e18;
char ma[MAXN][MAXN];
ll step[MAXN][MAXN];
struct nod{ int x, y; };
int dx[] = { 0,0,-1,1 };
int dy[] = { -1,1,0,0 };
int n, m, q;
void bfs() {
	queue<nod> Q;
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < m; j++) {
			step[i][j] = INF;
			for (int t = 0; t < 4; t++) {
				int ni = i + dx[t];
				int nj = j + dy[t];
				if (ni >= 0 && ni < n && nj >= 0 && nj < m
					&& ma[ni][nj] == ma[i][j]) {
					Q.push({ i,j });
					step[i][j] = 0;
					break;
				}
			}
 
		}
	}
 
	while (!Q.empty()) {
		nod cur = Q.front();
		Q.pop();
 
		for (int i = 0; i < 4; i++) {
			int nx = cur.x + dx[i];
			int ny = cur.y + dy[i];
			if (nx >= 0 && nx < n && ny >= 0 && ny < m && step[nx][ny] == INF) {
				step[nx][ny] = step[cur.x][cur.y] + 1;
				Q.push({ nx, ny });
			}
		}
	}
}
int main() {
	cin >> n >> m >> q;
	for (int i = 0; i < n; i++) cin >> ma[i];
	bfs();
	while (q--) {
		int x, y;
		ll t;
		cin >> x >> y >> t;
		x--, y--;
		if (step[x][y] == INF || step[x][y] > t) cout << ma[x][y] << endl;
		else {
			t -= step[x][y];
			if (t & 1ll) cout << 1 - int(ma[x][y] - '0') << endl;
			else cout << ma[x][y] << endl;
		}
	}
}

你可能感兴趣的:(Codeforces)