1.9 构造

B. Find The Array

题意:给出序列a,S为a的所有元素之和。要求构造出一个序列b,使b中相邻元素为倍数关系,且b中元素与a中元素差值不能超过S/2.
思路:要求构造倍数关系,那么利用a元素的范围进行构造,构造出从1~\(2^{31}\),用二分选出与\(a_i\)相近的数字,由于每个构造出来的数字与原数字的差值不会超过它自己的一半,所以即使整个数组都改,也不会超过总和的一半。

int a[N];
 
//注意观察N的大小
void solve() {
	int n;
	cin >> n;
	for (int i = 1; i <= n; i ++) {
		int x;
		cin >> x;
		int pos = upper_bound(a, a + 31, x) - a;
		cout << a[pos - 1] << " \n"[i == n];
	}
}
 
int main() {
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int t = 1;
	a[0] = 1;
	for (int i = 1; i <= 31; i ++) a[i] = 1 << i;
	
	cin >> t;
	while (t--) {
		solve();
	}
	
	return 0;
}

\[\]

C. Ping-pong

题意:Alice有x点体力,Bob有y点体力,每次击球消耗一点,问最后两人分别赢了多少场
思路:题目只是问最终会赢多少,没说要最小。所以答案就是x-1,y。每个人赢得自己体力的场次,Alice先击球,所以会被Bob抵消一个。

void solve() {
	int x, y;
	int resx, resy;
	cin >> x >> y;
	cout << x - 1 << ' ' << y <<  endl;
}

\[\]

B. Jumps

题意:起点为0,要到达坐标为x的点。每次跳跃可以跳i各单位或者后退一个单位。问最少需要多少次
思路:累加即可,直到和大于等于x,如果正好是x+1,则多走一步:向后退一个单位,否则在1~i次跳跃中,选择一次将其改为向后一格即可

void solve() {
	int x;
	cin >> x;
	int cnt = 0, sum = 0;
	for (int i = 1; i <= 1e6; i ++) {
		if (sum >= x) {
			if (sum - x == 1) cnt ++;
			break;
		}else sum += i, cnt ++;
	}
	
	cout << cnt << endl;
}

\[\]

D. Number into Sequence

题意:给出一个数字n,要求将n分解为若干因数,且是前面的因数都可以整除后面的的最长序列
思路:将n的所有因数各自的数量存在map中,然后找到具有最多数量的因数k,输出前k - 1个,然后将最后一个乘入剩余没用到的因数中

void solve() {
	LL n, x;
	cin >> n;
	x = n;
	map<LL, LL> mp;
	for (LL i = 2; i * i <= n; i ++) {
		while (n % i == 0) {
			mp[i] ++;
			n /= i;
		} 
	}
	
	LL maxv = -INF, tmp;
	
	for (auto i : mp) {
		if (i.second > maxv) {
			maxv = i.second;
			tmp = i.first;
		}
	}
	
	if (maxv < 0) {
		cout << 1 << endl;
		cout << n << endl;
		return ;
	}
	
	x /= pow(tmp, maxv);
	
	cout << maxv << endl;
	
	for (auto i : mp) {
		if (i.second == maxv) {
			for (int j = 1; j <= i.second - 1; j ++) {
				cout << i.first << " ";
			}
			cout << x * i.first << endl;
			break;
		}
	}
	
}

总结:对于构造题,首先要读懂题目意思,然后下手。其次还是得多练,感觉构造就是纯靠猜,需要多掌握几种变换方式,如需要相邻数具有倍数关系,则可以用2的幂次来构造

posted @ 2023-01-09 22:34  nobodyL  阅读(31)  评论(0)    收藏  举报