Codeforces Round #711 (Div. 2)(A-D)

Codeforces Round #711 (Div. 2)

A

A. GCD Sum

题意

给一个\(n\) 求 最小的\(x ( x \geq n)\) 使 \(gcd(x的各位和,x) > 1\)

sol

暴力即可,显然不会T

code

int f(int x) {
	int sum = 0;
	while(x) {
		sum += x % 10;
		x /= 10;
	}
	return sum;
}
void solve() {
	cin >> n;
	for(int i = n; ; i++) {
		if(__gcd(f(i),i) != 1) {
			cout << i << "\n";
			return;
		}
	}
}

B

B. Box Fitting

题意

\(n\) 个长度为 \(a_i\) 高度为\(1\) 的矩形,和一个长度为\(m\)的大矩形,不能竖着放,求放完\(n\)个矩形后最小的大矩形的高度为多少

sol

\(multiset\) 二分 或者 维护一个优先队列都可

先从大到小排序,用一个multiset容器储存留下的空隙的长度,

枚举贪心,找到所有空隙中大于等于当前矩形长的空隙,减去即可

如果容器为空或者当前矩形长度比容器中最大值都大,需要重新开一层

code

int n,m;
int a[maxn];
void solve() {
	cin >> n >> m;
	for(int i = 1; i <= n; i++) {
		cin >> a[i];
	}
	multiset<int> s;
	s.clear();
	int ans = 1;
	s.insert(m);
	sort(a+1,a+1+n,greater<int> () );
	for(int i = 1; i <= n; i++) {
		while(s.empty() || (a[i] > *--s.end())) {
			ans++;
			s.insert(m);
		}
		auto p = s.lower_bound(a[i]);
		int tmp = *p - a[i];
		s.erase(p);
		s.insert(tmp);
	} 
	cout << ans << "\n";
}

C

C. Planar Reflections

题意

sol

\(dp[i][j]\) 表示某个粒子衰变年龄为\(j\) 前方还有\(i\) 个平面,

粒子会分成两个,继续向右走且衰变年龄不变 \(dp[i][j] += dp[i-1][j]\)

另一个向左走且衰变年龄减\(1\) \(dp[i][j] += dp[n-i][j-1]\) 一共有\(n\) 个平面. 向左走就是走之前走过的,也就是\(n-i\)

转移方程即为

\[dp[i][j] = dp[n-i][j-1] + dp[i-1][j] \]

初始化的时候平面为\(0\)的情况和粒子为一的情况都初始化为\(1\)即可

注意需要先枚举粒子,

code

int n,m;
int dp[maxn][maxn];
const int mod = 1e9 + 7;
void solve() {
	cin >> n >> m;
	CLR(dp,0);
	for(int i = 1; i <= n; i++) {
		dp[i][1] = 1;
	}
	for(int i = 1;  i <= m; i++) {
		dp[0][i] = 1;
	}
	for(int j = 1; j <= m; j++) {
		for(int i = 1; i <= n; i++) {
			dp[i][j] = (dp[n-i][j-1] + dp[i-1][j]) % mod;
		}
	}
	cout << dp[n][m] << "\n";
}

D

D. Bananas in a Microwave

题意

\(n\)组数和一个\(m\),每组包含三个数\(t,x,y\),初始化\(k\)\(0\)\(t = 1\) 时,\(k += x, 否则,k *= x\) ,且可以执行\([0,y]\)次,求\([1,m]\)\(k\)能到达每个数的最短时间

sol

暴力再加一点点优化.

首先想到\(O(nm^2)\)做法,直接暴力枚举判断即可,考虑优化到\(O(nm)\),在枚举每\([1,f]\)的时候,对于求得的数,如果已经出现过,则直接\(break;\)

假设当前枚举到\(m_i\) 求得的数为\(m_j\),那么\(m_j = m_i + n * x (n\in[1,f])\)\(m_j\)在之前已经出现过,

也就说明枚举\([0,m]\)的时候必会枚举到\(m_j\), 而\(m_j\)也会进行\(m_j + n * x (n\in[1,f])\) 可以很容易发现这两次次枚举中重复枚举了\([m_j,m]\) 之间的可能的数,所以当枚举到\(m_j\)\(m_j\)出现过的时候,直接跳出,后面的数由\(m_j\)继续枚举即可

可以发现这样复杂度就会降低到\(O(nm)\) , 因为\([0,m]\)区间中的数最多不会枚举超过两次

注意枚举\([1,n]\)的时候,每一次的起点是由上一次决定的,所以需要新开一个临时的数组存储这一次中数的状态.

code

int n,m;
#define int long  long
int a[maxn],b[maxn],c[maxn],ans[maxn];
std::vector<bool> v(maxn+1,0);
void solve() {
	cin >> n >> m;
	for(int i = 1; i <= n; i++) {
		cin >> a[i] >> b[i] >> c[i];
	}
	v[0] = 1;
	for(int i = 1; i <= n; i++) {
		auto d = v;
		for(int j = 0; j <= m; j++) {
			if(!v[j]) continue;
			if(j == 0 && a[i] == 2) continue;
			int p = j;
			for(int k = 1; k <= c[i]; k++) {
				if(a[i] == 1) {
					p = p + (b[i] + 100000 - 1)/100000;
					
				}
				else {
					p = (p * b[i] + 100000 - 1)/100000;
				}
				if(p > m || v[p]) break;
				ans[p] = i;
				d[p] = 1;
			}
		}
		v = d;
	}
	for(int i = 1; i <= m; i++) {
		cout << (ans[i] ? ans[i] : -1) << " \n"[i == m];
	}
}

posted @ 2021-03-30 20:34  EnthalpyDecreaser  阅读(41)  评论(0编辑  收藏  举报