CF 1167 E.Range Deleting & F.Scalar Queries | edu round 65
(有任何问题欢迎留言或私聊 && 欢迎交流讨论哦
Catalog
Problem:传送门
Portal
原题目描述在最下面。
E.Range Deleting
- 题意:
给你一段长度为值域为的序列,。
问有多少对满足,原序列删除值在范围内的数字后,序列单调不递减。
- 观察:
如果原序列本来就单调不递减,那答案就是。
令表示值第一次出现的位置,表示值最后一次出现的位置。
若序列本来不是单调不递减,就是存在满足:。
我们找到第一次出现矛盾的值和最后一次出现矛盾的值。即,。
观察可知:必须满足:。
- 解析:
从上面我们得到了种的上界和的下界。
考虑枚举,找到能满足条件的最大的,那么剩下的做左端点肯定也是满足条件的。这个道理应该很明显。
显然如果你从大到小的枚举,他们满足条件的最大的肯定是单调不递增的。
然后就随便计数了。就这样找,while(rs[x-1] > ls[i+1]) -- x;
因为你只要知道删除后,能满足即可。
- 细节:
因为有的数字没有出现过,所以找的时候,先离散化一下在找比较方便。
比如: 。没有出现,这时候。因为。
还有就是对于没出现过的数字他的怎么赋值呢?
因为在算答案贡献的时候,只关心小数字的和大数字的。
所以对不存在的数就:。 - 总结:
只要你发现了那个观察,这个题就是一个傻逼题啊。
#include<bits/stdc++.h>
#define fi first
#define se second
#define iis std::ios::sync_with_stdio(false)
#define eb emplace_back
#define o2(x) (x)*(x)
#define all(x) (x).begin(), (x).end()
#define BASE_MAX 62
#define debug(x) cout << "[" << x << "]\n"
#define endl "\n"
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
inline LL read(){
LL x=0;int f=0;char ch=getchar();
while (ch<'0'||ch>'9') f|=(ch=='-'),ch=getchar();
while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return x=f?-x:x;
}
inline void write(LL x) {
if(x==0){putchar('0'),putchar('\n');return;}
if(x < 0) {putchar('-');x=-x;}
static char s[23];int l = 0;
while(x!=0)s[l++]=x%10+48,x/=10;
while(l)putchar(s[--l]);
putchar('\n');
}
template<class T>T Max(T a1,T a2){ return a1>a2?a1:a2; }
template<class T>T Max(T a1,T a2,T a3){ return Max(a1,Max(a2,a3)); }
template<class T>T Max(T a1,T a2,T a3,T a4){ return Max(a1,a2,Max(a3,a4)); }
template<class T>T Min(T a1,T a2){ return a1<a2?a1:a2; }
template<class T>T Min(T a1,T a2,T a3){ return Min(a1,Min(a2,a3)); }
template<class T>T Min(T a1,T a2,T a3,T a4){ return Min(a1,a2,Min(a3,a4)); }
const int INF = 0x3f3f3f3f;
const LL INFLL = 0x3f3f3f3f3f3f3f3fLL;
const int HMOD[] = {1000000007, 1000000009};
const LL BASE[] = {1572872831, 1971536491};
const int MXN = 1e6 + 7;
int n, m;
int ar[MXN];
int ls[MXN], rs[MXN];
int main() {
n = read(), m = read();
std::vector<int> vs; vs.eb(0);
for(int i = 1; i <= n; ++i) ar[i] = read(), rs[ar[i]] = i, vs.eb(ar[i]);
for(int i = n; i >= 1; --i) ls[ar[i]] = i;
ls[m+1] = n+1;
for(int i = 2; i <= m; ++i) if(rs[i] == 0) rs[i] = rs[i-1];
for(int i = m; i >= 1; --i) if(ls[i] == 0) ls[i] = ls[i+1];
//for(int i = 0; i <= m + 1; ++i) printf("%d %d*\n", ls[i], rs[i]);
int x = -1, y = -1;
sort(all(vs)); vs.erase(unique(all(vs)), vs.end());
for(int i = 1; i < vs.size(); ++i) if(ls[vs[i]] < rs[vs[i-1]]){
x = vs[i]; break;
}
for(int i = vs.size()-2; i >= 0; --i) if(rs[vs[i]] > ls[vs[i+1]]){
y = vs[i]; break;
}
//printf("%d %d\n", x, y);
if(x == -1) {
write((LL)m*(m+1)/2);
return 0;
}
LL ans = 0;
for(int i = m; i >= y; --i) {
while(rs[x-1] > ls[i+1]) -- x;
ans += x;
//debug(x);
}
write(ans);
return 0;
}
F.Scalar Queries
- 题意:
求。,数组是把原数组的部分从小到大排序后得到的新数组。 - 人尽皆知:
首先,。这个式子应该是随便算的吧?
对每个数字算贡献,数字包含它的区间有个,贡献就是:。 - 解析:
还是算单个数字的贡献。
考虑如果有一个数字,它比小。那么只要在一个区间内,这个的存在肯定会让值的贡献增加一次。
那么这个使得增加的总贡献是多少次呢?
答案是:若在前面:;若在后面:。
既然这样,我就从前往后和从后往前算两次算贡献即可。
很明显这个东西用一个树状数组维护就可以了。相当于权值线段树吧?就是每个点代表的是权值,维护的是他的下标值,就是他的位置。
看代码就懂了。
#include<bits/stdc++.h>
#define fi first
#define se second
#define iis std::ios::sync_with_stdio(false)
#define eb emplace_back
#define o2(x) (x)*(x)
#define all(x) (x).begin(), (x).end()
#define BASE_MAX 62
#define debug(x) cout << "[" << x << "]\n"
#define endl "\n"
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
inline LL read(){
LL x=0;int f=0;char ch=getchar();
while (ch<'0'||ch>'9') f|=(ch=='-'),ch=getchar();
while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return x=f?-x:x;
}
inline void write(LL x) {
if(x==0){putchar('0'),putchar('\n');return;}
if(x < 0) {putchar('-');x=-x;}
static char s[23];int l = 0;
while(x!=0)s[l++]=x%10+48,x/=10;
while(l)putchar(s[--l]);
putchar('\n');
}
int lowbit(int x) {return x&(-x);}
template<class T>T Max(T a1,T a2){ return a1>a2?a1:a2; }
template<class T>T Max(T a1,T a2,T a3){ return Max(a1,Max(a2,a3)); }
template<class T>T Max(T a1,T a2,T a3,T a4){ return Max(a1,a2,Max(a3,a4)); }
template<class T>T Min(T a1,T a2){ return a1<a2?a1:a2; }
template<class T>T Min(T a1,T a2,T a3){ return Min(a1,Min(a2,a3)); }
template<class T>T Min(T a1,T a2,T a3,T a4){ return Min(a1,a2,Min(a3,a4)); }
const int INF = 0x3f3f3f3f;
const LL INFLL = 0x3f3f3f3f3f3f3f3fLL;
const int HMOD[] = {1000000009, 1004535809};
const LL BASE[] = {1572872831, 1971536491};
const int mod = 1e9 + 7;
const int MXN = 1e6 + 7;
LL bit[MXN];
void bit_add(int x, int v, int N) {while(x <= N+1) bit[x] += v, x += lowbit(x);}
LL bit_sum(int x) {LL ans=0;for(;x;x-=lowbit(x))ans+=bit[x];return ans%mod;}
int n, m;
LL ar[MXN], ans;
int br[MXN];
std::vector<int> vs;
int get_id(int x) {return lower_bound(all(vs), x)-vs.begin()+1;}
int main() {
#ifndef ONLINE_JUDGE
freopen("E://ADpan//in.in", "r", stdin);
//freopen("E://ADpan//out.out", "w", stdout);
#endif
n = read();
for(int i = 1; i <= n; ++i) ar[i] = read(),vs.eb(ar[i]),ans=(ans+ar[i]*i%mod*(n-i+1)%mod)%mod;
sort(all(vs));
assert((int)vs.size() == n);
for(int i = 1; i <= n; ++i) {
br[i] = get_id(ar[i]);
ans = (ans + bit_sum(br[i]-1)*(n-i+1)%mod*ar[i]%mod)%mod;
bit_add(br[i], i, n);
}
for(int i = 0; i <= n+1; ++i) bit[i] = 0;
for(int i = n; i >= 1; --i) {
ans = (ans + bit_sum(br[i]-1)*i%mod*ar[i]%mod)%mod;
bit_add(br[i], n-i+1, n);
}
write((ans%mod+mod)%mod);
return 0;
}