update
This commit is contained in:
parent
5037f4d54e
commit
393e17bd1f
53
src/7/20/T371062s1.cpp
Normal file
53
src/7/20/T371062s1.cpp
Normal file
@ -0,0 +1,53 @@
|
||||
#include <algorithm>
|
||||
#include <cstdio>
|
||||
#include <deque>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
using ll = long long;
|
||||
|
||||
ll n,p,q,x,y,ans=std::numeric_limits<ll>::max();
|
||||
std::string s;
|
||||
|
||||
int main(){
|
||||
scanf("%lld%lld%lld%lld%lld",&n,&p,&q,&x,&y);
|
||||
std::cin>>s;
|
||||
for(ll msk=0;msk<(1ll<<n);msk++){
|
||||
std::string ns = s;
|
||||
ll nans{};
|
||||
for(ll i=0;i<ns.size();i++){
|
||||
if((1ll<<i)&msk){
|
||||
if(ns[i]=='+'){
|
||||
ns[i]='-';
|
||||
}else{
|
||||
ns[i]='+';
|
||||
}
|
||||
nans+=x;
|
||||
}
|
||||
}
|
||||
std::deque dq(ns.begin(),ns.end());
|
||||
for(ll i=0;i<n;i++){
|
||||
ll now{p};
|
||||
for(auto it = dq.begin();it!=dq.end();it++){
|
||||
if((*it)=='+'){
|
||||
now++;
|
||||
}else{
|
||||
if(now==0){
|
||||
goto next;
|
||||
}
|
||||
now--;
|
||||
}
|
||||
}
|
||||
if(now==q){
|
||||
ans=std::min(ans,nans);
|
||||
}
|
||||
next:;
|
||||
auto eit = --dq.end();
|
||||
char ec = *eit;
|
||||
dq.erase(eit);
|
||||
dq.push_front(ec);
|
||||
nans+=y;
|
||||
}
|
||||
}
|
||||
printf("%lld\n",ans);
|
||||
}
|
160
src/7/20/T635780.md
Normal file
160
src/7/20/T635780.md
Normal file
@ -0,0 +1,160 @@
|
||||
为了解决这个问题,我们需要找到给定数组中所有连续子段和中的前k小个数的和。由于子段的数量是O(n²)的,直接枚举所有子段并排序在n较大时(如10^6)是不可行的。因此,我们采用二分答案结合树状数组和离散化的高效方法。
|
||||
|
||||
### 方法思路
|
||||
1. **前缀和计算**:首先计算数组的前缀和数组`pre`,其中`pre[i]`表示从`a[1]`到`a[i]`的和。
|
||||
2. **离散化**:将前缀和数组`pre`中的值进行离散化处理,以便在树状数组中高效查询。
|
||||
3. **二分答案**:通过二分查找确定第k小的子段和`X0`。具体地,我们使用`count(X)`函数统计子段和不超过X的个数,通过二分调整X的值,直到找到满足条件的最小X0。
|
||||
4. **计算前k小子段和的和**:利用`count_sum(X0-1)`计算所有小于X0的子段和的总和,然后加上剩余的k - cnt_less个X0的值,得到最终结果。
|
||||
|
||||
### 解决代码
|
||||
```cpp
|
||||
#include <bits/stdc++.h>
|
||||
using namespace std;
|
||||
typedef long long ll;
|
||||
const int maxn = 1000010;
|
||||
|
||||
int n;
|
||||
ll k;
|
||||
ll a[maxn];
|
||||
ll pre[maxn];
|
||||
vector<ll> d;
|
||||
int m;
|
||||
int id[maxn];
|
||||
|
||||
struct Fenw {
|
||||
vector<ll> c_cnt, c_sum;
|
||||
int size;
|
||||
void init(int n) {
|
||||
size = n;
|
||||
c_cnt.assign(n+1, 0);
|
||||
c_sum.assign(n+1, 0);
|
||||
}
|
||||
void add_cnt(int i, ll v) {
|
||||
for (; i <= size; i += i & -i)
|
||||
c_cnt[i] += v;
|
||||
}
|
||||
void add_sum(int i, ll v) {
|
||||
for (; i <= size; i += i & -i)
|
||||
c_sum[i] += v;
|
||||
}
|
||||
ll query_cnt(int i) {
|
||||
if (i <= 0) return 0;
|
||||
ll res = 0;
|
||||
for (; i; i -= i & -i)
|
||||
res += c_cnt[i];
|
||||
return res;
|
||||
}
|
||||
ll query_sum(int i) {
|
||||
if (i <= 0) return 0;
|
||||
ll res = 0;
|
||||
for (; i; i -= i & -i)
|
||||
res += c_sum[i];
|
||||
return res;
|
||||
}
|
||||
} fenw;
|
||||
|
||||
void discrete() {
|
||||
d.clear();
|
||||
for (int i = 0; i <= n; i++)
|
||||
d.push_back(pre[i]);
|
||||
sort(d.begin(), d.end());
|
||||
d.erase(unique(d.begin(), d.end()), d.end());
|
||||
m = d.size();
|
||||
for (int i = 0; i <= n; i++) {
|
||||
id[i] = lower_bound(d.begin(), d.end(), pre[i]) - d.begin() + 1;
|
||||
}
|
||||
}
|
||||
|
||||
ll count_func(ll X) {
|
||||
fenw.init(m);
|
||||
for (int i = 1; i <= n; i++) {
|
||||
fenw.add_cnt(id[i], 1);
|
||||
}
|
||||
int j = 0;
|
||||
ll cnt_total = 0;
|
||||
for (int l = 1; l <= n; l++) {
|
||||
ll key = pre[l-1] + X;
|
||||
while (j < m && d[j] <= key)
|
||||
j++;
|
||||
if (j > 0) {
|
||||
ll cnt1 = fenw.query_cnt(j);
|
||||
cnt_total += cnt1;
|
||||
}
|
||||
fenw.add_cnt(id[l], -1);
|
||||
}
|
||||
return cnt_total;
|
||||
}
|
||||
|
||||
pair<ll, ll> count_sum_func(ll X) {
|
||||
fenw.init(m);
|
||||
for (int i = 1; i <= n; i++) {
|
||||
fenw.add_cnt(id[i], 1);
|
||||
fenw.add_sum(id[i], pre[i]);
|
||||
}
|
||||
int j = 0;
|
||||
ll cnt_total = 0;
|
||||
ll sum_total = 0;
|
||||
for (int l = 1; l <= n; l++) {
|
||||
ll key = pre[l-1] + X;
|
||||
while (j < m && d[j] <= key)
|
||||
j++;
|
||||
if (j > 0) {
|
||||
ll cnt1 = fenw.query_cnt(j);
|
||||
ll sum1 = fenw.query_sum(j);
|
||||
cnt_total += cnt1;
|
||||
sum_total += (sum1 - pre[l-1] * cnt1);
|
||||
}
|
||||
fenw.add_cnt(id[l], -1);
|
||||
fenw.add_sum(id[l], -pre[l]);
|
||||
}
|
||||
return {cnt_total, sum_total};
|
||||
}
|
||||
|
||||
int main() {
|
||||
scanf("%d%lld", &n, &k);
|
||||
for (int i = 1; i <= n; i++) {
|
||||
scanf("%lld", &a[i]);
|
||||
}
|
||||
pre[0] = 0;
|
||||
for (int i = 1; i <= n; i++) {
|
||||
pre[i] = pre[i-1] + a[i];
|
||||
}
|
||||
discrete();
|
||||
|
||||
ll L = 0, R = pre[n];
|
||||
while (L < R) {
|
||||
ll mid = (L + R) >> 1;
|
||||
if (count_func(mid) >= k) {
|
||||
R = mid;
|
||||
} else {
|
||||
L = mid + 1;
|
||||
}
|
||||
}
|
||||
ll X0 = L;
|
||||
pair<ll, ll> res;
|
||||
if (X0 - 1 < 0) {
|
||||
res = {0, 0};
|
||||
} else {
|
||||
res = count_sum_func(X0 - 1);
|
||||
}
|
||||
ll cnt_less = res.first;
|
||||
ll sum_less = res.second;
|
||||
ll cnt_equal = k - cnt_less;
|
||||
ll ans = sum_less + cnt_equal * X0;
|
||||
printf("%lld\n", ans);
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
### 代码解释
|
||||
1. **前缀和计算**:首先计算数组`a`的前缀和数组`pre`,用于快速计算任意子段和。
|
||||
2. **离散化**:将前缀和数组`pre`中的值排序并去重,生成离散化数组`d`,并建立映射`id`,将原前缀和值映射到离散化后的下标。
|
||||
3. **二分查找第k小的子段和**:
|
||||
- 使用`count_func(X)`函数统计子段和不超过`X`的个数。该函数利用树状数组高效维护当前右端点前缀和,并通过移动指针`j`避免重复二分查找。
|
||||
- 通过二分调整`X`的值,直到找到满足条件的最小`X0`,使得子段和不超过`X0`的个数至少为`k`。
|
||||
4. **计算前k小子段和的和**:
|
||||
- 使用`count_sum_func(X0-1)`计算所有小于`X0`的子段和的总和`sum_less`及个数`cnt_less`。
|
||||
- 剩余的子段和均为`X0`,个数为`k - cnt_less`。
|
||||
- 最终结果为`sum_less + (k - cnt_less) * X0`。
|
||||
|
||||
该方法高效地利用了二分答案和树状数组,结合离散化处理,确保在较大数据规模下仍能在合理时间内求解。
|
3
src/7/20/T635780fix.cpp
Normal file
3
src/7/20/T635780fix.cpp
Normal file
@ -0,0 +1,3 @@
|
||||
int main(){
|
||||
|
||||
}
|
@ -1,4 +1,3 @@
|
||||
#include <cstdio>
|
||||
int main(){
|
||||
printf("[%10.c]\n",'^');
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user