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(){
|
int main(){
|
||||||
printf("[%10.c]\n",'^');
|
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user