假期前的最后一次比赛,写完这篇就收拾收拾准备回家~
暂时都是做出来的题目,没做出来的等过两天再补题吧。
A:
由于可以包含自身,而最大因数必然是自身,故答案显然为n。
B:
看到数据范围,首先想到应该是有固定结论或单次不超过O(log(target))的解法。
首先,由于每次操作都要乘2,所以除非一开始就有一个瓶子的体积与目标相等,否则若目标为奇数,即不可完成。
否则,如果目标<max(a,b),假设a>b,那么只要从A瓶中倒掉
2
a
−
t
a
r
g
e
t
2
\frac {2a-target}{2}
22a−targetml即可达成目标。
否则,假设a>b,可以采取贪心的策略,先将B中的液体全部倒入A中,然后每次从A中向B中到1ml,直到2(a-1)≥target时多倒一些就可以。
代码如下:
if(t==m||t==n) printf("0\n");
else if(t&1) printf("-1\n");
else {
if(m<n) swap(m,n);
if(t<m) printf("1\n");
else {
int res=1;
m=(m+n)*2;
n=0;
//不用计算最后一次倒了多少
while(m<t) {
m=(m-1)*2;
n=(n+1)*2;
res++;
}
printf("%d\n",res);
}
}
D:
可以很自然地写出暴力解法:
for(int i=0; i<n; i++) {
int now=a[i];
for(int j=i; j<n; j++) {
now|=a[j];
if(now&1) {
res++;
//printf("[%d,%d]\n",i,j);
}
}
}
但这种方法的复杂度是远远不够的。
容易知道一个区间存在至少一个奇数是区间按位或结果为1的充要条件。考虑以下数据:
6
2 6 7 8 10 6
不难发现,奇数7“控制”的区间为:
[
i
,
j
]
[i,j]
[i,j]且
i
∈
[
1
,
3
]
,
j
∈
[
i
,
n
]
i \in[1,3],j \in[i,n]
i∈[1,3],j∈[i,n]
这样一来,它能对答案做出3 * (n-3+1)的贡献。推广到一般情况,位于i位置上的奇数能对答案做出i(n-i+1)的贡献。
但如果有多个奇数这个方法便会出现大量重复。一种解决方法是:让任何一个奇数都只能“控制”它后面和它前面直到上一个奇数之后的位置。那么我们只要记录上一个奇数出现的位置即可。
int lastOdd=-1;
for(int i=0; i<n; i++) {
if(a[i]&1) {
res+=(i-lastOdd)*(n-i);
lastOdd=i;
}
}
赛后补题1.17