冷静
题意:
q
q
q 个查询,每次查询
[
1
,
n
]
[1,n]
[1,n] 中,所含最小质因子
>
=
k
>=k
>=k 的数的个数
q
<
=
3
e
6
,
n
i
,
k
i
<
=
3
e
6
q<=3e6,n_i,k_i<=3e6
q<=3e6,ni,ki<=3e6
思路:
二维偏序问题
查询满足
(
i
<
=
n
,
f
(
i
)
>
=
k
)
(i<=n,f(i)>=k)
(i<=n,f(i)>=k) 的
i
i
i 的数量
开一个树状数组,按
n
n
n 从小到大,加入每个数的最小质因子。
线性筛预处理出每个数的最小质因子
注意细节:树状数组修改的区间终点不是
n
n
n,而是
m
a
x
n
−
9
maxn - 9
maxn−9
code:
#include<bits/stdc++.h>
#define endl '\n'
#define ll long long
using namespace std;
const int maxn = 3e6 + 9;
const int mod = 1e9 + 7;
ll n, m;
int p[maxn], vis[maxn];
void xxs()
{
for(int i = 2; i <= maxn - 9; ++i)
{
if(!vis[i]) p[++p[0]] = i, vis[i] = i;
for(int j = 1; j <= p[0] && i * p[j] <= maxn - 9; ++j)
{
vis[i * p[j]] = p[j];
if(i % p[j] == 0) break;
}
}
}
struct node
{
int n, k, id;
bool operator<(const node &B)const{
return n < B.n;
}
}a[maxn];
int q;
int ans[maxn], c[maxn];
void update(int i, int k){// 单点修改,在 i 的位置 + 1
while(i <= maxn - 9) c[i] += k, i += i & (-i);
}
int qry(int i, int res = 0){
while(i){
res += c[i]; i -= i & (-i);
}return res;
}
void work()
{
cin >> q;
for(int i = 1; i <= q; ++i)
cin >> a[i].n >> a[i].k, a[i].id = i;
sort(a + 1, a + 1 + q);
for(int i = 1, j = 2; i <= q; ++i)
{
while(j <= a[i].n) update(vis[j], 1), ++j;// 最小质因子为 vis[++j] 的数的数量 + 1
ans[a[i].id] = a[i].n - 1 - qry(a[i].k - 1);// 2-n 的所有数都根据其最小质因子加到相应的位置
// 查询最小质因子小于 k 的数的数量,总数量减去即可,注意减去1
}
for(int i = 1; i <= q; ++i)
cout << ans[i] << endl;
}
int main()
{
ios::sync_with_stdio(0);
// int TT;cin>>TT;while(TT--)
xxs();
work();
return 0;
}
终别
题意:
n
n
n 个怪兽,第
i
i
i 个有
a
i
a_i
ai 的血量,每次斩击可以使得连续三个位置的怪兽血量减
1
1
1,还有一个可以使用一次的魔法,可以直接消灭两个相邻的怪兽。求打败所有怪兽最小的斩击次数
思路:
贪心
不考虑使用魔法的情况
a
1
a_1
a1 显然要被杀死,那么我们肯定选择连续的三个一起使用斩击才是最优的,杀死
a
1
a_1
a1,然后
a
2
,
a
3
a_2,a_3
a2,a3,减少
a
1
a_1
a1 大小的血量(减完之后的怪兽血量要保证
>
=
0
>=0
>=0;杀死
a
2
.
.
.
a_2...
a2...,这样依次递推下去,直至杀死最后一个怪兽,这样的斩击花费就是最优的。
考虑使用魔法
考虑枚举使用魔法的位置,但是我们需要
O
(
1
)
O(1)
O(1) 的查询杀死其他位置需要的斩击次数
可以预处理前缀和后缀花费数组,前缀数组预处理成杀死
[
1
,
i
−
1
]
[1,i-1]
[1,i−1] 的最小斩击次数,后缀同理
code:
#include<bits/stdc++.h>
#define endl '\n'
#define ll long long
using namespace std;
const int maxn = 1e6 + 9;
const int mod = 1e9 + 7;
ll n, m;
ll l[maxn], r[maxn], a[maxn], b[maxn];
void work()
{
cin >> n;
for(int i = 1; i <= n; ++i)
cin >> a[i], b[i] = a[i];
for(int i = 2; i <= n - 1; ++i)// 杀死 a_{i-1}
{
l[i] = l[i - 1] + a[i - 1];
a[i] = max(0ll, a[i] - a[i - 1]);
a[i + 1] = max(0ll, a[i + 1] - a[i - 1]);
}
for(int i = n - 1; i >= 2; --i)// 杀死 b_{i+1}
{
r[i] = r[i + 1] + b[i + 1];
b[i] = max(0ll, b[i] - b[i + 1]);
b[i - 1] = max(0ll, b[i - 1] - b[i + 1]);
}
ll ans = 1e18;
for(int i = 1; i < n; ++i)// l[i], i <= n - 1 r[i], i >= 2
ans = min(ans, l[i] + r[i + 1]);
cout << ans << endl;
}
int main()
{
ios::sync_with_stdio(0);
// int TT;cin>>TT;while(TT--)
work();
return 0;
}
处理答案部分也可以这么写
for(int i = 2, j = 1; i <= maxn - 9 && j <= n; ++i){
update(vis[i], 1);
while(i == a[j].x && j <= n){
ans[a[j].id] = a[j].x - 1 - qry(a[j].k - 1);
++j;
}
}