大工之星第一周题解
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)

浙公网安备 33010602011771号