大工之星第一周题解

T1 猫猫虫与积分变换

我们发现本题只需要模拟分治的过程,从小到大进行还原,即先处理区间\([1,2]\),然后是\([1,4]\)...\([1, 2^k]\) (\(k=log_2(n)\))

code:

#include <bits/stdc++.h>

using namespace std;

int n, temp, cnt, a[260], b[260];

signed main(void) {
	while (cin >> n) {
		if (n == 0) return 0;
		for (int i = 0; i < n; i++) cin >> a[i];
		for (int i = 1; i != n; i *= 2) {
			cnt = 0;
			for (int j = 0; j < i; j++) {
				b[cnt++] = (a[j] + a[j + i]) / 2;
				b[cnt++] = (a[j] - a[j + i]) / 2;
			}
			for (int j = 0; j < i; j++)
				a[i] = b[i];
			memcpy(a, b, i * 8);
		}
		for (int i = 0; i < n - 1; i++) cout << a[i] << ' ';
		cout << a[n - 1] << endl;
	}
	return 0;
}

T2 猫猫虫的礼物

在做这道题之前,我们需要会解决经典的背包问题。不会背包问题的可以去网上搜《背包九讲》。这道题独特的限制是,要求恰好不能再装了的方案数。我们可以先将礼物根据从小到大顺序排序。假设现在考虑 \(f_x\) 为目前为止花了 \(x\) 元的方案数,那我们倒序处理即前面\(i - 1\)个全取,则答案要累加所有 \(x + a_i > m\)\(f_x\)

code:

#include <bits/stdc++.h>

using namespace std;

const int mod = 1e9 + 7;
int a[1005], s[1005], f[1005];

signed main(void) {
	int n, m;
	scanf("%d%d", &n, &m);
	for(int i = 1; i <= n; i++)scanf("%d", &a[i]);
	sort(a + 1, a + n + 1);
	for(int i = 1; i <= n; i++)s[i] = s[i - 1] + a[i];
	if(s[n] <= m) {
		puts("1");
		return 0;
	}
	int ans = 0;
	f[0] = 1;
	for(int i = n; i >= 1; i--) {
		if(s[i - 1] <= m)
			for(int j = max(m - s[i - 1] - a[i] + 1, 0); j <= m - s[i - 1]; j++)ans = (ans + f[j]) % mod;
		for(int j = m; j >= a[i]; j--)f[j] = (f[j] + f[j - a[i]]) % mod;
	}
	printf("%d\n", ans);
	return 0;
}

T3 线段树

只需要用到线段树 区间查询 技巧即可。每次发现整个点都包含在所求区间内时,直接return 1,其余部分不做修改。

struct segT{
#define root 1,1,n
#define mid ((l+r)>>1)
#define lson (pos<<1)
#define rson (lson|1)
#define l_son lson,l,mid
#define r_son rson,mid+1,r
#define This pos,l,r
	ll qry(int pos,int l,int r,int L,int R){
		// cerr<<"pos="<<pos<<" l,r="<<l<<' '<<r<<'\n';
		if(L<=l&&r<=R) return 1;
		if(R<=mid) return qry(l_son,L,R);
		if(L>=mid+1) return qry(r_son,L,R);
		return qry(l_son,L,R)+qry(r_son,L,R);
	}
}T;

def getsum(l, r, s, t, p):
    # [l, r] 为查询区间, [s, t] 为当前节点包含的区间, p 为当前节点的编号
    if l <= s and t <= r:
        return 1  # 当前区间为询问区间的子集时直接返回当前区间的和
    m = s + ((t - s) >> 1)
    sum = 0
    if l <= m:
        sum = sum + getsum(l, r, s, m, p * 2)
    # 如果左儿子代表的区间 [s, m] 与询问区间有交集, 则递归查询左儿子
    if r > m:
        sum = sum + getsum(l, r, m + 1, t, p * 2 + 1)
    # 如果右儿子代表的区间 [m + 1, t] 与询问区间有交集, 则递归查询右儿子
    return sum

T4 没结果

在行动之前,我们没法直接假设结果。起码我是这样认为的。

本题输出'no result'获得满分。

print('no result')

T5 茉莉雨

数学&构造

本质上\(n\)的值域可以较大(比如和int同阶),本题把这个范围缩小到100以内,所以直接暴力枚举四个数,稍加剪枝,应该也可以通过。

正解是,直接赋值: \(a=1,b=n-3,c=1,d=1\),不难验证这是正确的。

n = int(input())
print(1,n-3,1,1)
posted @ 2025-03-16 21:36  EternalEpic  阅读(123)  评论(0)    收藏  举报